Ответ 1
наконец, с помощью
GROUP BY
DATEPART(YEAR, DT.[Date]),
DATEPART(MONTH, DT.[Date]),
DATEPART(DAY, DT.[Date]),
DATEPART(HOUR, DT.[Date]),
(DATEPART(MINUTE, DT.[Date]) / 10)
нравится, когда я делаю
SELECT [Date]
FROM [FRIIB].[dbo].[ArchiveAnalog]
GROUP BY [Date]
как указать период группы?
MS SQL 2008
2nd Edit
Я пытаюсь
SELECT MIN([Date]) AS RecT, AVG(Value)
FROM [FRIIB].[dbo].[ArchiveAnalog]
GROUP BY (DATEPART(MINUTE, [Date]) / 10)
ORDER BY RecT
изменено% 10 на 10. Возможно ли сделать вывод даты без миллисекунд?
наконец, с помощью
GROUP BY
DATEPART(YEAR, DT.[Date]),
DATEPART(MONTH, DT.[Date]),
DATEPART(DAY, DT.[Date]),
DATEPART(HOUR, DT.[Date]),
(DATEPART(MINUTE, DT.[Date]) / 10)
Я супер опоздал на вечеринку, но это не отражено ни в одном из существующих ответов:
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
10
и MINUTE
можно изменить на любое число и DATEPART
соответственно.DATETIME
, что означает:
SELECT
даст вашему выходу столбец с довольно обрезанным выводом на указанном вами уровне.'2000'
- это "якорная дата", вокруг которой SQL будет выполнять математику даты. Джереон обнаружил ниже, что вы встречаете целочисленное переполнение с предыдущей привязкой (0
), когда вы группируете последние даты по секундам или миллисекундам. †SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
AS [date_truncated],
COUNT(*) AS [records_in_interval],
AVG(aa.[value]) AS [average_value]
FROM [friib].[dbo].[archive_analog] AS aa
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
ORDER BY [date_truncated]
Если ваши данные охватывают века, ‡, использующий одну дату привязки для second- или миллисекундную группировку, все равно столкнется с переполнением. Если это происходит, вы можете попросить каждую строку привязать сравнение биннинга к его собственной дате в полночь:
Используйте DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)
вместо '2000'
, где бы оно ни отображалось выше. Ваш запрос будет полностью нечитаемым, но он будет работать.
Альтернативой может быть CONVERT(DATETIME, CONVERT(DATE, aa.[date]))
в качестве замены.
† 2 32 & asymp; 4.29E + 9, поэтому, если ваш DATEPART
- SECOND
, вы получаете 4,3 миллиарда секунд с каждой стороны, или "якорь & plusmn; 136 лет". Аналогично, 2 32 миллисекунды равны & asymp; 49,7 дней.
‡ Если ваши данные действительно охватывают века или тысячелетия и все еще с точностью до секунды или миллисекунды & hellip; Поздравляем! Что бы вы ни делали, продолжайте делать это.
В T-SQL вы можете:
SELECT [Date]
FROM [FRIIB].[dbo].[ArchiveAnalog]
GROUP BY [Date], DATEPART(hh, [Date])
или
с помощью минутного использования DATEPART(mi, [Date])
или
на 10 минут используйте DATEPART(mi, [Date]) / 10
(как предположил Тимоти)
В течение 10-минутного интервала вы бы
GROUP BY (DATEPART(MINUTE, [Date]) / 10)
Как уже упоминалось tzup и Pieter888... чтобы сделать часовой интервал, просто
GROUP BY DATEPART(HOUR, [Date])
Должно быть что-то вроде
select timeslot, count(*)
from
(
select datepart('hh', date) timeslot
FROM [FRIIB].[dbo].[ArchiveAnalog]
)
group by timeslot
(Не уверен на 100% о синтаксисе - я больше похож на Oracle)
В Oracle:
SELECT timeslot, COUNT(*)
FROM
(
SELECT to_char(l_time, 'YYYY-MM-DD hh24') timeslot
FROM
(
SELECT l_time FROM mytab
)
) GROUP BY timeslot
Оригинальный ответ автора дал работы довольно хорошо. Чтобы расширить эту идею, вы можете сделать что-то вроде
group by datediff(minute, 0, [Date])/10
который позволит вам группироваться более длительным периодом, чем 60 минут, скажем, 720, что составляет полдня и т.д.
Для MySql:
GROUP BY
DATE(`your_date_field`),
HOUR(`your_date_field`),
FLOOR( MINUTE(`your_date_field`) / 10);
declare @interval tinyint
set @interval = 30
select dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0), sum(Value_Transaction)
from Transactions
group by dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0)
Мое решение - использовать функцию для создания таблицы с интервалами дат, а затем присоединить эту таблицу к данным, которые я хочу сгруппировать, используя интервал дат в таблице. Интервал даты может быть легко выбран при представлении данных.
CREATE FUNCTION [dbo].[fn_MinuteIntervals]
(
@startDate SMALLDATETIME ,
@endDate SMALLDATETIME ,
@interval INT = 1
)
RETURNS @returnDates TABLE
(
[date] SMALLDATETIME PRIMARY KEY NOT NULL
)
AS
BEGIN
DECLARE @counter SMALLDATETIME
SET @counter = @startDate
WHILE @counter <= @endDate
BEGIN
INSERT INTO @returnDates VALUES ( @counter )
SET @counter = DATEADD(n, @interval, @counter)
END
RETURN
END
Для SQL Server 2012, хотя я считаю, что он будет работать в SQL Server 2008R2, я использую следующий подход, чтобы сократить время до миллисекунды:
DATEADD(MILLISECOND, -DATEDIFF(MILLISECOND, CAST(time AS DATE), time) % @msPerSlice, time)
Это работает:
@ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
@rms = @ms % @msPerSlice
DATEADD(MILLISECOND, [email protected], time)
К сожалению, поскольку это переполнение с микросекундами и меньшими единицами, поэтому для больших, более точных наборов данных потребуется использовать менее удобную фиксированную точку.
Я не строго оценил это, и у меня нет больших данных, поэтому ваш пробег может отличаться, но производительность не была заметно хуже, чем другие методы, проверенные на нашем оборудовании и наборах данных, а также выплата в удобстве разработчика для произвольной нарезки делает это стоящим для нас.
select from_unixtime( 600 * ( unix_timestamp( [Date] ) % 600 ) ) AS RecT, avg(Value)
from [FRIIB].[dbo].[ArchiveAnalog]
group by RecT
order by RecT;
замените два 600 на любое количество секунд, которые вы хотите сгруппировать.
Если вам это нужно часто, и таблица не меняется, как следует из названия Archive, вероятно, было бы немного быстрее преобразовать и сохранить дату (и время) как unixtime в таблице.
Я знаю, что опоздал на шоу с этим, но я использовал это - довольно простой подход. Это позволяет получить 60-минутные срезы без каких-либо проблем с округлением.
Select
CONCAT(
Format(endtime,'yyyy-MM-dd_HH:'),
LEFT(Format(endtime,'mm'),1),
'0'
) as [Time-Slice]
Это легко
GROUP BY HOUR(yourDateField)