TSQL, используя пункт Time in Where - PullRequest
0 голосов
/ 19 декабря 2011

У меня есть измерения температуры, хранящиеся в таблице, каждая мера имеет действительную дату / время, НО логически день измерения начинается с полудня (а не полночи-ночи).Например, мера, выполненная в 18.09.2011 г. в 09:00:00, будет принадлежать 18.09.2011 г. «день измерения», но мера, выполненная в 18.09.2011 г. 13:00:00, уже принадлежит 19.09.2011 г.«день измерения».

Итак, теперь я хочу выполнить некоторые статистические запросы, например, «Средняя температура» между 09–11 в каждом «Дне измерения», это делается:

-- Select the AVG temp between 09-11    
select MeasureDate, AVG(Temp) from @d
where Time between '09:00:00' and '11:00:00'
Group by MeasureDate

Но если я хочу, чтобы средняя температура была между 23: 00-01: 00, я должен использовать другой запрос (время «между» здесь не работает):

-- Select the AVG temp between 23:00-01:00
select MeasureDate, AVG(Temp) from @d
where (Time>='23:00:00' or Time<='01:00:00')
Group by MeasureDate

Есть ли простой способ получить тот же запросподдержать оба сценария?В идеале я хочу иметь функцию, которая получает @ из / @ в качестве параметров и возвращает результат в виде таблицы.

Ниже приведен полный пример, который вы можете запустить.Спасибо!

DECLARE @d TABLE ([Date] DATE, [Time] TIME(0), Temp DECIMAL(6,3), [MeasureDate] DATE); 

INSERT @d VALUES 
('2011-09-18','09:00:00',38.15, '2011-09-18'),
('2011-09-18','10:00:00',38.20, '2011-09-18'),
('2011-09-18','11:00:00',38.22, '2011-09-18'),
('2011-09-18','23:00:00',38.22, '2011-09-19'), -- Note the difference here between Date and     MeasureDate
('2011-09-19','00:00:00',38.17, '2011-09-19'),
('2011-09-19','01:00:00',38.32, '2011-09-19'),

('2011-09-19','09:00:00',39.15, '2011-09-19'),
('2011-09-19','10:00:00',39.20, '2011-09-19'),
('2011-09-19','11:00:00',39.22, '2011-09-19'),
('2011-09-19','23:00:00',39.22, '2011-09-20'), -- Note the difference here between Date and     MeasureDate
('2011-09-20','00:00:00',39.17, '2011-09-20'),
('2011-09-20','01:00:00',39.32, '2011-09-20');

-- Select the AVG temp between 09-11    
select MeasureDate, AVG(Temp) from @d
where Time between '09:00:00' and '11:00:00'
Group by MeasureDate

-- Select the AVG temp between 23:00-01:00
select MeasureDate, AVG(Temp) from @d
where (Time>='23:00:00' or Time<='01:00:00')
Group by MeasureDate

1 Ответ

0 голосов
/ 19 декабря 2011

Краткий (и неэффективный) ответ: предварительно обработайте ваше значение Time (и, конечно, ваше значение сравнения); Значения «ВРЕМЯ» меняются, поэтому вам не нужно беспокоиться о добавлении или удалении дней:

SELECT MeasureDate, AVG(Temp) 
FROM @d
WHERE DateAdd(Hour, 12, [Time]) >= DateAdd(Hour, 12, Convert(Time, '09:00:00'))
    AND DateAdd(Hour, 12, [Time]) < DateAdd(Hour, 12, Convert(Time, '11:00:00'))
GROUP BY MeasureDate

Это дает вам согласованные запросы, хотя, конечно, не особенно красиво. (вы можете предварительно обработать время в другом месте, нет необходимости делать это в SQL).

Более «правильный» подход с точки зрения производительности (если у вас есть или когда-либо нужен индекс для Time / MeasureTime, то есть), заключается в сохранении предварительно обработанного «MeasureTime» и непосредственном сравнении с ним:

SELECT MeasureDate, AVG(Temp) 
FROM @d
WHERE MeasureTime >= DateAdd(Hour, 12, Convert(Time, '09:00:00'))
    AND MeasureTime < DateAdd(Hour, 12, Convert(Time, '11:00:00'))
GROUP BY MeasureDate

«MeasureTime» может поддерживаться клиентским кодом или индексированным вычисляемым столбцом, или поддерживаться триггером - так много способов усилить вашу боль!

Обратите внимание, что в этих примерах я использовал версию «больше» и «меньше», а не «МЕЖДУ», потому что в моем опыте использование «МЕЖДУ» для дат / времени всегда неверно.

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