2009-05-21 4 views
1

Я храню события в 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 И EVENTDATE < = @DateEnd)

Спасибо,

+3

Вместо того, чтобы поиграть с получением последнего момента до полуночи (сложно, поскольку MS SQL Server является точным до определенной точки, и это также делает этот код проблематичным для передачи на другую СУБД), почему бы вам просто не использовать EventDate <@DateEnd вместо «<=»? –

+2

Всякий раз, когда вы хотите обрабатывать ведра диапазонов дат, подобных этому, предпочтительно использовать включенное условие на одной граничной и эксклюзивной с другой. То есть чище сказать <полуночи, а не <= полуночи-.003 секунды. – ahains

ответ

7

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

+2

Просто помните, что МЕЖДУ ВКЛЮЧЕН. –

+0

Правильно, примерно эквивалентно <= and a > = – TheTXI

0

Попробуйте следующее:

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

EDIT Чтобы отправить комментарий Tom H's: Мне никогда не удавалось индексировать поля даты; то, что всегда улучшалось для меня, было дополнительными целыми столбцами для обработки значений года и дня года и индексации их вместо этого.

+1

Что касается «самого быстрого», этот метод не подходит, поскольку он исключает использование любых индексов в EventDate. –

1

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

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

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

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

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

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

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

2

Ваше предложение 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), если ваша таблица большая.

+0

Разве вы не указали DateCol, а не какую-то формулу с DateCol? –

0

Я думаю, что это 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, и перемещать выражения прямо в запросе, но я не» t ожидаем, что это улучшит производительность и сделает инструкцию SQL труднее читать, вы обязательно захотите оставить комментарии ...

ГДЕ (EventDate> = CONV ERT (DATETIME, CONVERT (VARCHAR (10), @ DateStart, 20), 20) AND EventDate
Смежные вопросы