Để trả lời lý do tại sao bạn nhận được Thứ Hai mà không phải Chủ Nhật:
Bạn đang thêm một số tuần vào ngày 0. Ngày 0 là gì? 1900-01-01. Ngày 1900-01-01 là ngày gì? Thứ hai. Vì vậy, trong mã của bạn, bạn đang nói, bao nhiêu tuần đã trôi qua kể từ Thứ Hai, ngày 1 tháng 1 năm 1900? Hãy gọi đó là [n]. Được rồi, bây giờ hãy thêm [n] tuần vào Thứ Hai, ngày 1 tháng 1 năm 1900. Bạn không nên ngạc nhiên rằng điều này kết thúc là Thứ Hai. DATEADD
không có ý tưởng rằng bạn muốn thêm tuần nhưng chỉ cho đến khi bạn đến Chủ nhật, nó chỉ là thêm 7 ngày, sau đó thêm 7 ngày nữa, ... giống như DATEDIFF
chỉ công nhận các ranh giới đã được vượt qua. Ví dụ:cả hai đều trả về 1, mặc dù một số người phàn nàn rằng phải có một số logic hợp lý được tích hợp để làm tròn lên hoặc xuống:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Để trả lời cách nhận ngày Chủ nhật:
Nếu bạn muốn có một ngày Chủ nhật, thì hãy chọn một ngày cơ bản không phải là Thứ Hai mà là Chủ nhật. Ví dụ:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
Điều này sẽ không bị hỏng nếu bạn thay đổi DATEFIRST
của mình cài đặt (hoặc mã của bạn đang chạy cho người dùng có cài đặt khác) - với điều kiện là bạn vẫn muốn có một ngày Chủ nhật bất kể cài đặt hiện tại. Nếu bạn muốn hai câu trả lời đó cho jive, thì bạn nên sử dụng một hàm does phụ thuộc vào DATEFIRST
cài đặt, ví dụ:
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Vì vậy, nếu bạn thay đổi DATEFIRST
của mình cài đặt thành Thứ Hai, Thứ Ba, bạn có gì, hành vi sẽ thay đổi. Tùy thuộc vào hành vi bạn muốn, bạn có thể sử dụng một trong các chức năng sau:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
... hoặc ...
CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO
Bây giờ, bạn có rất nhiều lựa chọn thay thế, nhưng lựa chọn nào hoạt động tốt nhất? Tôi sẽ rất ngạc nhiên nếu có bất kỳ sự khác biệt lớn nào nhưng tôi đã thu thập tất cả các câu trả lời được cung cấp cho đến nay và chạy chúng qua hai bộ bài kiểm tra - một rẻ và một đắt. Tôi đã đo lường số liệu thống kê của khách hàng vì tôi không thấy I / O hoặc bộ nhớ đóng một phần trong hiệu suất ở đây (mặc dù chúng có thể phát huy tác dụng tùy thuộc vào cách sử dụng chức năng). Trong các thử nghiệm của tôi, kết quả là:
Truy vấn bài tập "rẻ":
HàmFunction - client processing time / wait time on server replies / total exec time
Gandarez - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday - 357/2158/2515 - 0:25.2
trailmax - 364/2160/2524 - 0:25.2
Curt - 424/2202/2626 - 0:26.3
Truy vấn chuyển nhượng "Đắt":
Function - client processing time / wait time on server replies / total exec time
Curt - 1003/134158/135054 - 2:15
Gandarez - 957/142919/143876 - 2:24
me Sunday - 932/166817/165885 - 2:47
me datefirst - 939/171698/172637 - 2:53
trailmax - 958/173174/174132 - 2:54
Tôi có thể chuyển tiếp chi tiết các bài kiểm tra của mình nếu muốn - dừng ở đây vì điều này đã trở nên khá dài. Tôi hơi ngạc nhiên khi thấy Curt's xuất hiện nhanh nhất ở phân khúc cao cấp, dựa trên số lượng phép tính và mã nội tuyến. Có lẽ tôi sẽ chạy một số bài kiểm tra kỹ lưỡng hơn và viết blog về nó ... nếu các bạn không phản đối việc tôi xuất bản các chức năng của bạn ở nơi khác.