Щоб відповісти, чому ви отримуєте понеділок, а не неділю:
Ви додаєте кількість тижнів до дати 0. Що таке дата 0? 1900-01-01. Яким був день 1900-01-01? Понеділок. Отже, у своєму коді ви говорите, скільки тижнів минуло з понеділка, 1 січня 1900 року? Назвемо це [n]. Гаразд, тепер додайте [n] тижнів до понеділка, 1 січня 1900 року. Ви не повинні дивуватися, що це закінчується понеділком. DATEADD
не уявляє, що ви хочете додати тижні, але лише доки не дійдете до неділі, це просто додавання 7 днів, потім додавання ще 7 днів, ... так само, як DATEDIFF
розпізнає лише межі, які були перетнуті. Наприклад, вони обидва повертають 1, хоча деякі люди скаржаться на те, що повинна бути вбудована якась розумна логіка для округлення вгору або вниз:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Щоб відповісти, як отримати неділю:
Якщо ви хочете неділю, виберіть базову дату, яка не є понеділком, а неділею. Наприклад:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
Це не порушиться, якщо ви зміните DATEFIRST
налаштування (або ваш код працює для користувача з іншим налаштуванням) - за умови, що ви все одно хочете неділю незалежно від поточного налаштування. Якщо ви хочете, щоб ці дві відповіді були джив, тоді вам слід використовувати функцію, яка залежить від DATEFIRST
налаштування, наприклад
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Тож якщо ви зміните DATEFIRST
налаштування на понеділок, вівторок, що у вас буде, поведінка зміниться. Залежно від того, яку поведінку ви хочете, ви можете використовувати одну з таких функцій:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
... або ...
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
Зараз у вас є безліч альтернатив, але яка з них працює найкраще? Я був би здивований, якщо б були якісь суттєві відмінності, але я зібрав усі надані відповіді і провів їх через два набори тестів - один дешевий і один дорогий. Я виміряв статистику клієнта, оскільки я не бачу тут вводу-виводу чи пам'яті, які відіграють роль у продуктивності (хоча вони можуть увійти в дію залежно від того, як використовується функція). У моїх тестах результати такі:
"Дешевий" запит призначення:
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
"Дорогий" запит призначення:
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
Я можу передати деталі своїх тестів за бажанням - зупиняючись тут, оскільки це вже стає досить затятим. Я був трохи здивований, побачивши, що Курт вийшов найшвидшим у верхній частині, враховуючи кількість обчислень та вбудований код. Можливо, я проведу кілька ретельніших тестів і буду писати про це в блозі ... якщо ви, хлопці, не заперечуєте проти того, щоб я публікував ваші функції деінде.
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
залишається незмінним незалежно від@@datefirst
налаштування, я думаю. З понеділка = 2.