如何按小时或10分钟分组时间


167

就像我做的时候

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date]

如何指定小组活动时间?

微软SQL 2008

第二次编辑

我尝试着

SELECT MIN([Date]) AS RecT, AVG(Value)
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY (DATEPART(MINUTE, [Date]) / 10)
  ORDER BY RecT

将%10更改为/10。是否可以使Date输出不带毫秒?

Answers:


213

终于完成了

GROUP BY
DATEPART(YEAR, DT.[Date]),
DATEPART(MONTH, DT.[Date]),
DATEPART(DAY, DT.[Date]),
DATEPART(HOUR, DT.[Date]),
(DATEPART(MINUTE, DT.[Date]) / 10)

11
我做到了ROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5,因此当我查看数据时,它与最近的时隙相关
hdost

7
年,月和日可以简化为DATE(DT.[Date])

@Keelan对我不起作用-但是CONVERT(date,DT。[Date])起作用。
丹·帕森森,

datepart(hour, workingPolicy.workingHours)/2.0给出1.5同时datepart(hour, '1900-01-01 09:00:30.000')/2.0给出了4.5,我不明白为什么?注意:workingPolicy.workingHours = 1900-01-01 09:00:30.000。请帮助
affanBajwa 18/12/29

65

我参加聚会太迟了,但是在任何现有的答案中都没有出现:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • 10MINUTE条件是可以改变的任何号码并且DATEPART分别。
  • 它是一个DATETIME值,表示:
    • 长时间间隔运行良好。(几年之间没有冲突。)
    • SELECT语句中包含它会为您的输出提供一列,并在您指定的级别截断漂亮的输出。
  • '2000'是一个“锚定日期”,SQL将围绕该日期执行日期数学运算。Jereonh 在下面发现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]

如果您的数据跨越几个世纪以来,使用二线单个锚日期或毫秒分组仍然会遇到溢出。如果发生这种情况,您可以要求每一行将合并比较锚定到其日期的午夜:

  • 使用DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)而不是'2000'上面出现的任何地方。您的查询将完全不可读,但可以使用。

  • 另一种可能是CONVERT(DATETIME, CONVERT(DATE, aa.[date]))替代品。

2 32 ≈4.29E + 9,所以如果你的DATEPART就是SECOND,你得到4.3十亿秒两边,或“锚±136年。” 同样,2 32毫秒等于≈49.7天。
如果您的数据实际上跨越了几个世纪或一千年,并且仍然精确到秒或毫秒……恭喜!无论您在做什么,都要继续做。


从特定的开始日期开始可以这样做吗?
皮兰德

1
@pylander好的。只需where在之前放置一个子句group by
Michael-Clay Shirky在哪里,

2
我懂了。那么将其更改/ 20 * 20为与以20分钟为间隔收集数据相同吗?抱歉,我现在正在努力学习数学。
凌晨

2
对于第二个DATEPART,我收到一条错误消息(The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.)。似乎MINUTE是您可以使用此方法的最小日期部分。
jeroenh

1
@jeroenh,你是对的。我添加了一个部分来谈论这一点。tldr:将更0改为'2000'(引号很重要!),然后重试SECOND
Michael-Clay Shirky在哪里,

17

在T-SQL中,您可以:

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date], DATEPART(hh, [Date])

要么

通过分钟使用 DATEPART(mi, [Date])

要么

使用10分钟DATEPART(mi, [Date]) / 10(如提摩太建议的)


1
GROUP BY [Date],DATEPART(hh,[Date])是一团糟,不是吗?
2011年

1
@nCdy应该没问题,否则您将收到一个错误“ ...在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中”
tzup 2011年

1
如何将整个日期和小时数同时分组?我只是在使用Min Date。
2011年

如果您使用Min(Date),那么您当然可以在Group By中取出Date。
tzup

3
分钟除以10将以10分钟为间隔创建分组,这是我所需要的。Modulo 10没有意义。
Tar

12

每隔10分钟,您将

GROUP BY (DATEPART(MINUTE, [Date]) / 10)

正如tzup和Pieter888所提到的...间隔一个小时,

GROUP BY DATEPART(HOUR, [Date])

2
但是在这里,我将1980年的会议记录与2011年的会议记录进行分组:SI需要关心它。
2011年

%是正确的数学吗?那不会创建10个群组。例如:1%10 = 9 2%10 = 8甚至不一定是正确的时间顺序分组。我认为只有正常的分界是正确的。除非%不是sql中的余数除法。
Steven

12
分钟除以10将以10分钟为间隔创建分组,这是我所需要的。Modulo 10没有意义。
Tar

同意焦油。分组没有意义。
MikeMurko '16

7

应该是这样的

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 

6

作者给出的原始答案效果很好。只是为了扩展这个想法,您可以做类似的事情

group by datediff(minute, 0, [Date])/10

这将使您可以分组更长的时间,然后是60分钟,例如720,这是半天等。


1
上面的MySQL查询是什么?
Biranchi

4

对于MySql:

GROUP BY
DATE(`your_date_field`),
HOUR(`your_date_field`),
FLOOR( MINUTE(`your_date_field`) / 10);

1

我的解决方案是使用一个函数来创建一个具有日期间隔的表,然后将该表与要使用表中日期间隔进行分组的数据连接起来。然后,在显示数据时可以轻松选择日期间隔。

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

1
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)

8
欢迎来到stackoverflow。您需要充分解释您的答案,这对网站上已有的其他10个答案有什么帮助。
Simon.SA,

0

对于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, -@rms, time)

不幸的是,由于这种溢出以微秒和较小的单位为单位,因此较大,较细的数据集将需要使用不太方便的固定点。

我尚未对此进行严格的基准测试,也无法使用大数据,因此您的里程可能会有所不同,但是性能并不比我们在设备和数据集上尝试的其他方法明显差,并且为任意切片而在开发人员中带来的便利使它值得为我们。


0
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并将其存储在表中可能会更快一些。


0

我知道我参加这个展览会很晚,但是我使用了这个-非常简单的方法。这样一来,您可以得到60分钟的片段,而没有任何取整问题。

Select 
   CONCAT( 
            Format(endtime,'yyyy-MM-dd_HH:'),  
            LEFT(Format(endtime,'mm'),1),
            '0' 
          ) as [Time-Slice]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.