Функция Floor() для даты и времени - SQL Server

http://sqlfiddle.com/

CREATE TABLE TEST
(
ID INT,
OrderNo int,
DateReceived datetime
)

INSERT INTO TEST (ID,OrderNo,DateReceived)
VALUES ('1', '3454', '07-20-2018 00:00:00')

Запрос:

DECLARE @StartDate datetime,
@EndDate datetime,
@FlooredStart datetime ,
@FlooredEnd datetime 

SET @StartDate = '07-20-18'
SET @EndDate = '07-20-18'
SET @FlooredStart  = CAST(FLOOR(CAST(@startDate AS FLOAT)) AS DATETIME)
SET @FlooredEnd = DATEADD(d, 1, CAST(FLOOR(CAST(@endDate AS FLOAT)) AS DATETIME))

SELECT * FROM TEST 
WHERE DateReceived = @FlooredStart and DateReceived < @FlooredEnd

В моей живой версии, если полученная дата оставлена ​​пустой, по умолчанию используется время 12:00:00 того дня. Так что для этого примера, если я ищу заказы 07-20-18, он не вернет заказ, который был размещен в 12:00:00 утра 07-20-18.

Так что я решил добавить>= к предложению

DECLARE @StartDate datetime,
@EndDate datetime,
@FlooredStart datetime ,
@FlooredEnd datetime 

SET @StartDate = '07-20-18'
SET @EndDate = '07-20-18'
SET @FlooredStart  = CAST(FLOOR(CAST(@startDate AS FLOAT)) AS DATETIME)
SET @FlooredEnd = DATEADD(d, 1, CAST(FLOOR(CAST(@endDate AS FLOAT)) AS 
DATETIME))

SELECT * FROM TEST 
-- WHERE DateReceived BETWEEN @StartDate AND @EndDate
WHERE DateReceived >= @FlooredStart and DateReceived < @FlooredEnd

Результат:

| ID | OrderNo |         DateReceived |
|----|---------|----------------------|
|  1 |    3454 | 2018-07-20T00:00:00Z |

Мне просто интересно, правильно ли я понял эту логику? И кто-нибудь может объяснить мне точно, что делает функция floor(). Я понимаю, что это вычисление первого дня года / месяца, но нужно ли это здесь? Я посмотрел в Интернете, и я не мог найти окончательный ответ нигде.

Спасибо

1 ответ

Решение

Вместо того, чтобы использовать floor чтобы "обрезать" часть времени, используйте только дату date тип:

DECLARE @StartDate date = '20180720', @EndDate date='20180720'

SELECT * FROM TEST 
WHERE cast(DateReceived date) between @startdate and @enddate

или только на одну дату:

SELECT * FROM TEST 
WHERE cast(DateReceived date) = @startdate 

Обратите внимание, что я использую неразделенный литерал даты. Это единственный однозначный формат даты. Другим однозначным форматом является полный формат ISO8601 для типов datetime. Двузначные годы просто умоляют о неверной интерпретации пути.

cast(DateReceived date) преобразует datetime значения в DateReceived в date ценности. Обычно плохая идея применять функции к полям, потому что это не позволяет оптимизатору запросов использовать какие-либо индексы. SQL Server понимает cast( ... as date) хотя и конвертирует

cast(DateReceived date) = @startdate 

Для запроса диапазона, эквивалентного DateReceived between @startdate at 00:00 but before the next day at 00:00, позволяя использовать любые индексы на DateReceived

Другие вопросы по тегам