Để trả lời tại sao bạn lại nhận được Thứ Hai mà không phải là 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, rồi thêm 7 ngày nữa, ... giống như DATEDIFF
chỉ nhận ra những ranh giới đã bị 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 cần 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 làm thế nào để có được một 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ị phá vỡ nếu bạn thay đổi DATEFIRST
cài đặt của mình (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 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 những hai câu trả lời cho jive, sau đó bạn nên sử dụng một chức năng mà không phụ thuộc vào các DATEFIRST
thiết lập, ví dụ như
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Vì vậy, nếu bạn thay đổi DATEFIRST
cài đặt của mình thành Thứ Hai, Thứ Ba, những gì bạn có, 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 là...
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ẽ 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ẻ":
Function - 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 dòng. 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.
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
vẫn không đổi bất kể@@datefirst
cài đặt tôi nghĩ. Với Thứ Hai = 2.