Сравнение дат SQL Server по месяцам и годам
У меня возникли проблемы с определением наилучшего способа сравнения дат в SQL на основе только месяца и года.
Мы делаем расчеты на основе дат и, поскольку выставление счетов происходит ежемесячно, дата месяца привела к большим помехам.
Например
DECLARE @date1 DATETIME = CAST('6/15/2014' AS DATETIME),
@date2 DATETIME = CAST('6/14/2014' AS DATETIME)
SELECT * FROM tableName WHERE @date1 <= @date2
Приведенный выше пример не будет возвращать строки, поскольку @date1 больше, чем @date2. Поэтому я хотел бы найти способ вывести день из уравнения.
Аналогично, следующая ситуация дает мне горе по той же причине.
DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME),
@date2 DATETIME = CAST('6/15/2014' AS DATETIME),
@date3 DATETIME = CAST('7/1/2014' AS DATETIME)
SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3
Я сделал встроенные преобразования дат для получения первого дня и последнего дня месяца для указанной даты.
SELECT *
FROM tableName
WHERE date2 BETWEEN
DATEADD(month, DATEDIFF(month, 0, date1), 0) -- The first day of the month for date1
AND
DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, date2) + 1, 0)) -- The lastday of the month for date3
Должен быть более простой способ сделать это. Любые предложения?
Ответы
Ответ 1
Чтобы обрабатывать неравенства, например, между ними, мне нравится преобразовывать дату/время в представление YYYYMM, либо как строку, либо целое число. В этом примере:
DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME),
@date2 DATETIME = CAST('6/15/2014' AS DATETIME),
@date3 DATETIME = CAST('7/1/2014' AS DATETIME);
SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3;
Я бы написал запрос как:
SELECT *
FROM tableName
WHERE year(@date2) * 100 + month(@date2) BETWEEN year(@date1) * 100 + month(@date1) AND
year(@date3) * 100 + month(@date1);
Ответ 2
Вы можете отфильтровать месяц и год заданной даты на текущую дату следующим образом:
SELECT *
FROM tableName
WHERE month(date2) = month(getdate()) and year(date2) = year(getdate())
Просто замените метод GETDATE()
на нужную дату.
Ответ 3
Вы можете присоединиться к значениям MONTH
и YEAR
этих дат:
SELECT *
FROM tableName
WHERE YEAR(@date1) = YEAR(@date2) AND MONTH(@date1) = MONTH(@date2)
Ответ 4
Во-первых, я бы использовал недвусмысленный формат дат, например, стандартный 'YYYYMMDD'
а не '6/15/2014'
вы использовали. Блог Аарона Бертрана объясняет гораздо лучше, чем я, различные способы, которыми это может пойти не так:
Вредные привычки: неправильная обработка запросов даты/диапазона
Для конкретной проблемы ваш последний запрос, который находит первые и последние дни месяцев (для даты1 и даты3), по моему мнению, находится на правильном пути. Вам нужны первые дни месяцев (первый день даты 1 и первый день следующего месяца для даты 3), если вы избегаете зла BETWEEN
: Что общего между МЕЖДУ и дьяволом?
SELECT *
FROM tableName
WHERE date2 >= DATEADD(month, DATEDIFF(month, '19000101', @date1), '19000101')
AND date2 < DATEADD(month, 1+DATEDIFF(month, '19000101', @date3), '19000101') ;
Запрос работает как есть, независимо от типа данных date2
(DATE
, DATETIME
, DATETIME2
или SMALLDATTEIME
).
Бонусный момент, индексы на date2
будут учитываться оптимизатором таким образом.
Улучшение, согласно (еще одному) сообщению в блоге Аарона, чтобы избежать проблемы с оценкой мощности при оценке выражений с помощью DATEDIFF()
:
Производственные сюрпризы и предположения: DATEDIFF
SELECT *
FROM tableName
WHERE date2 >= CONVERT(DATE, DATEADD(day, 1 - DAY(@date1), @date1))
AND date2 < DATEADD(month, 1,
CONVERT(DATE, DATEADD(day, 1 - DAY(@date3), @date3))) ;
Ответ 5
Вы можете использовать форматирование даты, например, "ггггММ", поэтому будет выбран только месяц в том же году.
SELECT *
FROM tableName
WHERE FORMAT(date_month_bill, 'yyyyMM') < FORMAT(DATEADD(MONTH, -1, GETDATE()), 'yyyyMM')
AND FORMAT(date_month_bill, 'yyyyMM') > FORMAT(DATEADD(MONTH, -3, GETDATE()), 'yyyyMM')