25 августа 2017 г.

MSSQL DATETIME2, DATETIME truncate минуты, секунд.

В какой то момент может понадобится  возможность в SQL запросе по полю типа DATETIME или DATETIME2 производить сравнение дат с какой то конкретной датой, отбросив при этом минуты, секунды, миллисекунды. Для дат, которые лежат в настоящие годы, это можно сделать без каких либо проблем через DATEADD и DATEDIFF. Пример использования с обрезанием до минут:

SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, '2017-08-25 00:00'), 0)

В случае, если требуется обрезание до секунд, миллисекунд или любой другой составляющей даты достаточно поменять первый параметр метода DATEADD и DATEDIFF на нужный тип. Список типов одинаков и описан на msdn каждого метода.

Все было бы хорошо, но есть ложка дёгтя в бочке с медом. DATEDIFF возвращает количество прошедших минут, секунд, миллисекунд с 1900-01-01 00:00:00 при этом возвращаемое значение INT. Это значит:
  • Даты до 1900 года будут иметь отрицательное значение
  • Мы имеем ограничение на возвращаемое значение, равное диапазону значений INT, а это ровняется от -2,147,483,648 до +2,147,483,647.
  • Чем меньшую единицу измерения времени мы хотим обрезать, тем ближе к 1900 году должна быть дата в таблице.
При этом, максимальный год для DATETIME и DATETIME2 это 9999. И если в таблице будет присутствовать значение, которая будет приводить к переполнению INT при вычисление DATEDIFF - вы будете получать ошибку на ваш SQL запрос:
The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.
Для демонстрации можно выполнить запрос:

SELECT DATEDIFF(MINUTE, 0, '9999-01-01 00:00')


Как ещё обрезать время?


Можно самому собрать нужное время, при этом обрезав его до нужного значения. Пример обрезания до минут:

DECLARE @Time DateTime2 = '9999-08-25 12:30:33.123'

SELECT 'Before: ', @Time
Select 'After:', CAST(
(
STR(YEAR(@Time)) + '-' +
STR(MONTH(@Time)) + '-' +
STR(DAY(@Time)) + ' ' +
STR(DATEPART(HOUR, @Time)) + ':' +
STR(DATEPART(MINUTE, @Time)))
AS DATETIME2)
 
Before:  9999-08-25 12:30:33.1230000 
After:   9999-08-25 12:30:00.0000000
 
Как видно, достаточно сформировать нужную строку, извлекая отдельные периоды времени, далее используя метод CAST преобразовать полученную строку к DATETIME либо DATETIME2. Данную операцию необходимо применять к каждой дате в таблице перед сравнением с ней.

Комментариев нет:

Отправить комментарий