T-SQL DateDiff - разделение по «полному часу назад», а не «разу минуты повернули 00 с тех пор» - PullRequest
5 голосов
/ 20 июля 2010

У меня есть таблица с временными метками, и я хочу разбить эту таблицу на часовые интервалы, начиная с настоящего момента и возвращаясь назад на пару часов. Я не могу получить нужные мне результаты с помощью функции T-SQL DATEDIFF , поскольку она подсчитывает, сколько раз минутная стрелка проходит 12 между двумя датами - я хочу, сколько раз их минутная стрелка проходит там, где сейчас между отметкой времени и сейчас.

Есть ли простой способ сделать это в T-SQL?

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

Пример данных:

TimeStamp
*********
2010-07-20 11:00:00.000
2010-07-20 10:44:00.000
2010-07-20 10:14:00.000
2010-07-20 11:00:00.000
2010-07-20 11:40:00.000
2010-07-20 10:16:00.000
2010-07-20 13:00:00.000
2010-07-20 12:58:00.000

Текущий запрос:

SELECT TimeStamp, DATEDIFF(HOUR, TimeStamp, CURRENT_TIMESTAMP) AS Diff FROM ...

Результаты:

    TimeStamp                   Diff
    *********                   ****
    2010-07-20 11:00:00.000     2
    2010-07-20 10:44:00.000     3
    2010-07-20 10:14:00.000     3
    2010-07-20 11:00:00.000     2
    2010-07-20 11:40:00.000     2
    2010-07-20 10:16:00.000     3
    2010-07-20 13:00:00.000     0
    2010-07-20 12:58:00.000     1

Что бы я предпочел:

    -- The time is now, for the sake of the example, 13:40

    TimeStamp                   Diff
    *********                   ****
    2010-07-20 11:00:00.000     3 -- +1
    2010-07-20 10:44:00.000     3
    2010-07-20 10:14:00.000     4 -- +1
    2010-07-20 11:00:00.000     3 -- +1
    2010-07-20 11:40:00.000     2 or 3 -- edge case, I don't really care which
    2010-07-20 10:16:00.000     4 -- +1
    2010-07-20 13:00:00.000     1 -- +1
    2010-07-20 12:58:00.000     1

Я отметил результаты, которые изменились на +1. Кроме того, мне все равно, если это 0 или 1, но в основном, если сейчас 13:40, я хочу, чтобы промежутки времени, которые получают то же значение, были

    12:40-13:40    1 (or 0)
    11:40-12:40    2 (or 1)
    10:40-11:40    3 (or 2)
    09:40-10:40    4 (or 3)

Ответы [ 3 ]

7 голосов
/ 20 июля 2010

Можете ли вы не просто использовать DATEDIFF(minute,.., а затем разделить результат на 60 и принять целочисленное значение. например,

 SELECT DATEDIFF(minute, '2010-07-20 06:00', GETDATE())/60

Я полагаю, что это будет неявно приведено как int, так как datediff возвращает int, оно дает целые часы без округления.

Чтобы использовать точный запрос из вашего обновленного сообщения:

SELECT TimeStamp, (DATEDIFF(minute, TimeStamp, CURRENT_TIMESTAMP) /60) AS Diff FROM ...
0 голосов
/ 21 июля 2010

Я бы использовал

FLOOR(24 * CAST(CURRENT_TIMESTAMP-[TimeStamp] as float))

Контрольный пример

DECLARE @GetDate datetime
set @GetDate = '2010-07-20 13:40:00.000';

WITH TestData As
(
select CAST('2010-07-20 11:00:00.000' AS DATETIME) AS [TimeStamp]  UNION ALL
select '2010-07-20 10:44:00.000'  UNION ALL    
select '2010-07-20 10:14:00.000'  UNION ALL   
select '2010-07-20 11:00:00.000'  UNION ALL   
select '2010-07-20 11:40:00.000'  UNION ALL   
select '2010-07-20 10:16:00.000'  UNION ALL   
select '2010-07-20 13:00:00.000'  UNION ALL  
select '2010-07-20 12:58:00.000'
)

SELECT [TimeStamp], FLOOR(24 * CAST(@GetDate-[TimeStamp] as float))  AS Diff
FROM TestData

Результаты

(Вам потребуетсядобавьте 1, чтобы получить точные результаты, которые вы опубликовали, но вы говорите, что вас не беспокоит индекс 0 или 1)

TimeStamp               Diff
----------------------- ----------------------
2010-07-20 11:00:00.000 2
2010-07-20 10:44:00.000 2
2010-07-20 10:14:00.000 3
2010-07-20 11:00:00.000 2
2010-07-20 11:40:00.000 2
2010-07-20 10:16:00.000 3
2010-07-20 13:00:00.000 0
2010-07-20 12:58:00.000 0
0 голосов
/ 21 июля 2010

Вы можете сгруппировать по этому:

SELECT DateDiff(Hour, 0, GetDate() - TimeStamp)

Если вы хотите узнать время, которое это представляет, вычислите его обратно:

DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate())

Если вам не нравится вычитать даты,тогда это еще можно сделать, но становится немного сложнее.Вместо того, чтобы просто снимать в темноте, я разработал запрос, чтобы доказать, что это правильно.

SELECT
   TimeStamp,
   Now = GetDate(),
   HourDiff = DateDiff(Hour, 0, GetDate() - TimeStamp),
   HourCalc = DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate()),
   HourDiff2 = DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())),
   HourCalc2 = DateAdd(Hour, -DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())), GetDate())
FROM
   (
      SELECT DateAdd(Second, -3559, GetDate())
      UNION ALL SELECT DateAdd(Second, -3600, GetDate())
      UNION ALL SELECT DateAdd(Second, -3601, GetDate())
   ) x (TimeStamp)
   CROSS JOIN (
      SELECT 3599997 - DateDiff(Millisecond, 0, DateAdd(Hour, -DateDiff(Hour, 0, GetDate()), GetDate()))
   ) D (AdjustMs)

К сожалению, мне пришлось использовать свои знания разрешения типа datetime (1/300 секунды), таким образом3600000 - 3 = 3599997. Если бы корректировка в миллисекундах была рассчитана на основе TimeStamp вместо GetDate (), то в этом не было бы необходимости, но это было бы намного сложнее, поскольку большое выражение внутри производной таблицы D пришлось бы использовать дваждыв основном запросе замените AdjustMs.

Расчеты более сложны, чем может показаться необходимым, потому что вы не можете просто вычислить разницу в миллисекундах между случайными датами, иначе вы получите ошибку переполнения.Если вам известны возможные диапазоны дат, вам, возможно, удастся выполнить прямые миллисекундные вычисления с использованием другой даты привязки, нежели «19000101 00: 00: 00.000» (0 в вышеприведенных выражениях).

В секундудумал, что вы получите только 24+ дня миллисекунд в длинную подпись:

SELECT DateAdd(Millisecond, 2147483647, 0) = '1900-01-25 20:31:23.647'
...