【问题标题】:SQL SERVER Group Datetimestamps by MonthSQL SERVER 按月分组日期时间戳
【发布时间】:2018-11-12 10:47:34
【问题描述】:

在过去 3 年中,我每 15 分钟获取一次间隔数据(值)。 datetimestamp 的数据类型是 datetimeoffset(7)。 每个间隔的日期时间戳必须被解释为时间段的结束。

例如,日期时间戳 2017-01-01 00:00:00.0000000 +01:00 处的值 1.96 是周期 从 2016-12-31 23:45:00.0000000 +01:00 到 2017-01-01 00:00:00.0000000 +01:00

DateTime                            Value
2016-12-31 23:00:00.0000000 +01:00  2.0000000000
2016-12-31 23:15:00.0000000 +01:00  1.9600000000
2016-12-31 23:30:00.0000000 +01:00  2.0400000000
2016-12-31 23:45:00.0000000 +01:00  2.0000000000
2017-01-01 00:00:00.0000000 +01:00  1.9600000000
2017-01-01 00:15:00.0000000 +01:00  2.1200000000
2017-01-01 00:30:00.0000000 +01:00  2.0800000000
2017-01-01 00:45:00.0000000 +01:00  2.0000000000
2017-01-01 01:00:00.0000000 +01:00  2.0000000000

我想知道每月的总数。下面的查询给了我错误的结果,因为 datetimestamp 2017-01-01 00:00:00.0000000 +01:00 添加到 2017 年 1 月而不是 2016 年 12 月。

SELECT Year([datetimestamp])  AS [Year], 
       Month([datetimestamp]) AS [Month], 
       Sum([value])           AS [Total] 
FROM   [data] 
GROUP  BY Year([datetimestamp]), 
          Month([datetimestamp]) 
ORDER  BY [year], 
          [month]

【问题讨论】:

  • 转换为 UTC?
  • :sigh:这就是为什么(通常)你使用“结束”句点存储东西,而是使用“开始”句点存储。这样一来,如果您更改时间分辨率,则不需要特殊的指示符(即,如果您的分辨率达到 1 秒,@LukStorms 答案将不再有效)。它允许动态的、可变的、更容易的时期。这是因为时间(最容易被认为是)是连续的——也就是说,没有“结束”瞬间,只有开始和长度(以某种分辨率)。任何时候你记录一个“结束”,它真的是其他事情的开始......

标签: sql sql-server datetime group-by


【解决方案1】:

所以如果你减去一分钟,那么它会产生正确的年份和月份?

SELECT 
 YEAR(Dt) AS [Year],
 MONTH(Dt) AS [Month],
 SUM([Value]) AS [Total]
FROM (
  SELECT
   DATEADD(MINUTE, -1, [datetimestamp]) AS Dt,
   [Value]
  FROM [data]
) q
GROUP BY YEAR(Dt), MONTH(Dt)
ORDER BY [Year], [Month];

或者没有子查询

SELECT 
 YEAR(DATEADD(MINUTE, -1, [datetimestamp])) AS [Year],
 MONTH(DATEADD(MINUTE, -1, [datetimestamp])) AS [Month],
 SUM([Value]) AS [Total]
FROM [data]
GROUP BY YEAR(DATEADD(MINUTE, -1, [datetimestamp])), 
         MONTH(DATEADD(MINUTE, -1, [datetimestamp]))
ORDER BY [Year], [Month];

【讨论】:

  • @ZoharPeled OP说数据每15分钟固定一次。因此,查看该数据无论您选择 -15 还是 -1 都无关紧要。关键是要在前一年获得'2017-01-01 00:00:00'。
  • 是的,但您在这里依赖的是准确的时间戳。我知道它适用于这种情况,但如果时间戳不太准确,1 分钟可能不够。
  • 没错,但我会看看 OP 怎么说。似乎那些没有秒的时间戳是批量生成的。
【解决方案2】:

你可能会发现这更容易表达

SELECT YEAR(dts_start) AS [Year],
       MONTH(dts_start) AS [Month],
       SUM([Value]) AS [Total]
FROM data CROSS APPLY
     (VALUES (DATEADD(minute, -15, datetimestamp)) as v(dts_start)
GROUP BY YEAR(dts_start), MONTH(dts_start)
ORDER BY [Year], [Month];

您可能还会发现FORMAT() 很方便:

SELECT FORMAT(dts_start, 'yyyy-MM') AS yyyymm,
       SUM([Value]) AS [Total]
FROM data CROSS APPLY
     (VALUES (DATEADD(minute, -15, datetimestamp)) as v(dts_start)
GROUP BY FORMAT(dts_start, 'yyyy-MM')
ORDER BY yyyymm;

【讨论】:

  • 真的吗?按文本格式分组?虽然做日期/时间数学可能会消除命中索引的能力......
猜你喜欢
  • 1970-01-01
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多