Самый быстрый способ проверить диапазон дат - PullRequest
1 голос
/ 21 мая 2009

Я храню события в SQLServer 2005, где время наступления события имеет важное значение и должно храниться в базе данных. Какой самый быстрый способ записать проверку диапазона дат в предложении where, чтобы убедиться, что все в этот день выбрано?

В настоящее время, когда передаются @DateStart и @DateEnd, я устанавливаю @DateStart в полночь и устанавливаю @DateEnd в последний момент до полуночи как самое первое, что нужно для отслеживания всех возможных событий дня.

IF (@DateStart IS NOT NULL)
BEGIN
    SET @DateStart = CAST   (
                                (   CAST (DATEPART (yyyy,@DateStart) AS NVARCHAR(4)) +'/'+
                                    CAST (DATEPART (mm,@DateStart) AS NVARCHAR(2)) +'/'+
                                    CAST (DATEPART (dd,@DateStart) AS NVARCHAR(2)) +' '+
                                    '00:00:00.000'
                                )
                            AS DATETIME)
END

IF (@DateEnd IS NOT NULL)
BEGIN
    SET @DateEnd = CAST (
                            (   CAST (DATEPART (yyyy,@DateEnd) AS NVARCHAR(4)) +'/'+
                                CAST (DATEPART (mm,@DateEnd) AS NVARCHAR(2)) +'/'+
                                CAST (DATEPART (dd,@DateEnd) AS NVARCHAR(2)) +' '+
                                '23:59:59.997'
                            )
                            AS DATETIME
                        )
END

Так что предложение where очень легко читается:

ГДЕ (EventDate> = @DateStart AND EventDate <= @DateEnd) </p>

Спасибо

Ответы [ 6 ]

7 голосов
/ 21 мая 2009

Вы всегда можете использовать альтернативный синтаксис WHERE EventDate BETWEEN @DateStart AND @DateEnd

2 голосов
/ 21 мая 2009

Ваше предложение where будет выглядеть так:

WHERE DateCol >= DATEADD(dd, DATEDIFF(dd, 0, @DateStart), 0) --Midnight on the Start date
    AND DateCol < DATEADD(dd, DATEDIFF(dd, 0, @DateEnd + 1), 0) --Midnight of the day after End date

и все, что будет делать ваш оператор IF - это обрабатывать нулевые параметры (т.е. IF @DateEnd IS NULL THEN SET @DateEnd = @DateStart)

Возможно, вы хотите индексировать DATEADD (dd, DATEDIFF (dd, 0, DateCol), 0), если ваша таблица велика.

1 голос
/ 21 мая 2009

самый быстрый способ обрезать дату предыдущей полуночи:

DATEADD (день, DATEDIFF (день, «19010101», LastModifiedDate), «19010101»)

в следующую полночь:

DATEADD (день, DATEDIFF (день, «19010101», LastModifiedDate) +1, «19010101»)

Вы можете также обернуть это как встроенный UDF:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/05/23/reuse-your-code-with-cross-apply.aspx

0 голосов
/ 23 мая 2009

Я думаю, что этот T-SQL эквивалентен вашему коду:

    -- set time portion of @DateStart back to midnight
    SET @DateStart = CONVERT(DATETIME,CONVERT(VARCHAR(10),@DateStart,20),20)

    -- advance time portion of @DateEnd to last instant before next midnight
    SET @DateEnd = CONVERT(DATETIME,CONVERT(VARCHAR(11),@DateEnd,20)+'23:59:59.997',21)

Функция CONVERT будет обрабатывать NULLS, поэтому нет необходимости в отдельном тесте для значения NULL (если, конечно, вы не выполняете какую-то специальную обработку, отличную от того, что вы показываете, и не передаете значения NULL предикат запроса (т. е. предложение WHERE). Или, возможно, вы ожидаете, что многие аргументы будут равны NULL, и вы хотите избежать издержек при вызовах CONVERT.

Однако я согласен с рекомендацией Тома Х. и не путаюсь с вычитанием миллисекунд, а вместо этого устанавливаю @DateEnd в полночь следующего дня, например

    -- advance @DateEnd to midnight of following day
    SET @DateEnd = DATEADD(day,1,CONVERT(DATETIME,CONVERT(VARCHAR(10),@DateEnd,20),20))

и измените предикат, чтобы выполнить тест диапазона следующим образом:

WHERE (EventDate >= @DateStart AND EventDate < @DateEnd)

Вы можете избежать отдельных операторов SET и переместить выражения прямо в запрос, но я не ожидаю, что это повысит производительность и затруднит чтение оператора SQL, вы определенно захотите оставить комментарии ...

WHERE (EventDate> = CONVERT (DATETIME, CONVERT (VARCHAR (10), @ DateStart, 20), 20) И EventDate
0 голосов
/ 21 мая 2009

AlexK, вероятно, лучшая идея из всех. Единственное, о чем я бы беспокоился, это производительность использования функций в предикате.

Вы должны рассмотреть возможность добавления столбца с именем searchdate или чего-то подобного к вашей таблице, чтобы содержать дату без времени. Я бы также предложил проиндексировать этот столбец, особенно если вы будете много искать по данным столбца.

Когда вы выполняете запрос к этому столбцу, у вас не будет скалярных функций в SQL, чтобы лишить индексы их производительности.

Условие ... ну, дополнительное пространство для хранения, время для вставки данных (не так много здесь).

SQL Server 2008 лучше поддерживает типы данных только для дат. Вы также можете проверить это.

0 голосов
/ 21 мая 2009

Попробуйте это:

WHERE DATEPART(yyyy, EventDate) = DATEPART(yyyy, getdate()) 
      AND DATEPART(dy, EventDate) = DATEPART(dy, getdate())  --day of year

РЕДАКТИРОВАТЬ Чтобы ответить на комментарий Тома Х: Мне никогда не везло с индексами на полях даты; то, что всегда работало лучше для меня, это дополнительные целочисленные столбцы для обработки значений года и дня года и индексации их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...