Để trả lời lý do tại sao bạn đang nhận được một thứ hai và không phải là một Chủ nhật:
Bạn đang thêm một số tuần tới ngày 0. Ngày 0 là gì? 1900-01-01. Ngày nào là ngày 1900-01-01? 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]. Ok, bây giờ thêm [n] tuần đến 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à một 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 nhận được một chủ nhật, nó chỉ thêm 7 ngày, sau đó thêm 7 ngày nữa, ... giống như DATEDIFF
chỉ nhận ra ranh giới đã được vượt qua. Ví dụ, những cả hai trở lại 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 xây dựng trong để 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 như thế nào để có được một Chủ nhật:
Nếu bạn muốn một ngày chủ nhật, sau đó chọn ngày cơ sở không phải là ngày thứ Hai mà là ngày chủ nhật. Ví dụ:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
này sẽ không phá vỡ nếu bạn thay đổi DATEFIRST
thiết lập của bạn (hoặc mã của bạn đang chạy cho một người dùng với một môi trường khác) - với điều kiện là bạn vẫn muốn có một chủ nhật không phụ thuộc vào thiết lập 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 hàm không phụ thuộc vào cài đặt DATEFIRST
, ví dụ:
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Vì vậy, nếu bạn thay đổi cài đặt DATEFIRST
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 mà bạn muốn, bạn có thể sử dụng một trong những chức năng:
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 mà 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 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 thông qua hai bộ kiểm tra - một trong những giá rẻ và đắt tiền. Tôi đo số liệu thống kê khách hàng bởi 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ù những người có thể đi vào chơi tùy thuộc vào cách chức năng được sử dụng). Trong các thử nghiệm của tôi kết quả là:
"giá rẻ" truy vấn phân công:
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
"Đắt" truy vấn phân công:
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 các chi tiết của các bài kiểm tra của tôi nếu muốn - dừng lại ở đây vì điều này đã nhận được khá dài. Tôi hơi ngạc nhiên khi thấy Curt xuất hiện nhanh nhất ở cấp cao, với số lượng tính toán 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à blog về nó ... nếu các bạn không có bất kỳ phản đối nào để 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 thay đổi bất kể cài đặt' @@ datefirst' mà tôi nghĩ. Với Monday = 2. –