Ответ t-clausen.dk работает, но может быть неясно , почему работает (ни вам, ни разработчику, который придет за вами). Поскольку дополнительная ясность иногда достигается за счет краткости и производительности, я хотел бы объяснить, почему это работает, если вы предпочитаете использовать этот более короткий синтаксис.
SELECT t.*
FROM <table> t CROSS JOIN
(SELECT DATEDIFF(day, 0, getdate() - DATEDIFF(day, 0, getdate()) %7) lastmonday) a
WHERE t.yourdate >= a.lastmonday - 7 and yourdate < a.lastmonday
Как SQL Server хранит datetime
Внутренне
SQL Server хранит datetime
как два 4-байтовых целых числа; первые четыре байта представляют количество дней с 01.01.1900 (или до 01.01.1900 для отрицательных чисел), а вторые четыре байта представляют количество миллисекунд с полуночи.
Использование datetime
с int
или decimal
Поскольку datetime
хранится в виде двух 4-байтовых целых чисел, в T-SQL легко перемещаться между типами данных числовых и дат. Например, SELECT GETDATE() + 1
возвращает то же, что и SELECT DATEADD(day, 1, GETDATE())
, а CAST(40777.44281 AS datetime)
совпадает с 2011-08-24 10:37:38.783
.
1/1/1900
Поскольку первая целочисленная часть datetime представляет собой, как было упомянуто выше, количество дней с 01.01.1900 (также называемое эпохой SQL Server), CAST(0 as datetime)
по определению эквивалентно
1900-01-01 00:00:00
DATEDIFF (день, 0, GETDATE ())
Здесь все становится сложнее и веселее. Во-первых, мы уже установили, что когда 0
обрабатывается как дата, оно совпадает с 01.01.1900, поэтому DATEDIFF(day, '1/1/1900', GETDATE())
совпадает с DATEDIFF(day, 0, GETDATE())
- оба вернут текущее количество дней с 1 / 1/1900. Но подождите: текущее количество дней - это именно то, что представлено первыми четырьмя байтами даты и времени! В одном утверждении мы сделали две вещи: 1) мы удалили часть «времени», возвращаемую GETDATE()
, и у нас есть целочисленное значение, которое мы можем использовать для расчета для нахождения самого последнего воскресенья и предыдущего Понедельник немного легче.
по модулю 7 на понедельник
DATEDIFF(day, 0, GETDATE()) % 7
использует тот факт, что DATEPART(day, 0)
(что с риском переоценки точки совпадает с DATEPART(day, '1/1/1900')
) возвращает 2
(понедельник). 1 Следовательно, DATEDIFF(day, 0, GETDATE()) % 7
всегда будет указывать количество дней с понедельника до текущей даты.
1 Если вы не изменили поведение по умолчанию с помощью DATEFIRST
.
Самый последний понедельник
Это почти слишком тривиально для его собственного заголовка, но на этом этапе мы можем собрать все, что у нас так далеко:
GETDATE() - DATEDIFF(day, 0, GETDATE()) %7
дает вам самый последний понедельник
DATEDIFF(day, 0, GETDATE() - DATEDIFF(day, 0, GETDATE()) %7)
дает вам самый последний понедельник как целую дату, без временной части.
Но плакат хотел все с понедельника по воскресенье ...
Вместо использования оператора BETWEEN, который является включенным, опубликованный ответ исключил последний день, так что не было необходимости делать какие-либо сдвиги или вычисления, чтобы получить правильный диапазон дат:
t.yourdate >= a.lastmonday - 7
возвращает записи с датами, начиная с (или включая) полуночи второго по времени последнего понедельника
t.yourdate < a.lastmonday
возвращает записи с датами до (но не включая) полуночи самого последнего понедельника.
Я большой сторонник написания кода, который легко понять, как для вас, так и для разработчика, который придет после вас через год (который также может быть вами). Я считаю, что ответ, который я опубликовал ранее, должен быть понятен даже начинающим программистам на T-SQL. Однако ответ t-clausen.dk является кратким, хорошо работает и может встречаться в рабочем коде, поэтому я хотел дать некоторое объяснение, чтобы помочь будущим посетителям понять, почему это работает.