【问题标题】:SQL Server 2014 with GROUP BY on a timestamp and PIVOTSQL Server 2014 与时间戳和 PIVOT 上的 GROUP BY
【发布时间】:2016-11-06 21:18:24
【问题描述】:

这可能很容易,但我无法得到它,所以我想我会问。

我使用的是 SQL Server 2014,并且有一个包含以下列的表:

id, int
date, datetime
sensorId, varchar(45)
observedObjId, varchar(45)

我想要一个查询,我提供以下输入:

sensorId_1
sensorId_2
startDateTime
endDateTime
intervalAmount
intervalTime

然后输出将是一个结果集,其中有两个传感器 ID 作为列,每一行将是 startDateTime 和 endDateTime 之间的时间,按间隔分开 - 例如,5 分钟、1 小时、1 天等。那么交叉点处的值将是特定传感器观察到的 ObjId 数量的计数。

我从来没有得到它的 PIVOT 部分,因为我无法让 GROUP BY 部分正确。我正在搞乱按DATEPART(datepart, date) 分组,但这似乎失去了其余日期的上下文,因此效果不佳。

有什么建议吗?

【问题讨论】:

    标签: sql sql-server tsql sql-server-2014


    【解决方案1】:

    例如,对于基于DAY 的分组,我会像这样使用GROUP BY(在动态SQL 中实现基于指定传感器的动态列命名):

    DECLARE @sensorId_1 INT, 
            @sensorId_2 INT,
            @startDateTime DATETIME,
            @endDateTime DATETIME
    
    -- For example, return data for Sensors 3 and 7 within the month of Feb 2016
    SET @sensorId_1 = 3
    SET @sensorId_2 = 7
    SET @startDateTime = '2016-02-01'
    SET @endDateTime = '2016-03-01'
    
    DECLARE @sql NVARCHAR(MAX)
    
    SET @sql =
    'SELECT CAST([date] AS DATE) AS [Day], 
            SUM(CASE WHEN sensorId = ' + CONVERT(VARCHAR,@sensorId_1) + ' THEN 1 ELSE 0 END) AS Sensor_' + CONVERT(VARCHAR,@sensorId_1) + ',' +
          ' SUM(CASE WHEN sensorId = ' + CONVERT(VARCHAR,@sensorId_2) + ' THEN 1 ELSE 0 END) AS Sensor_' + CONVERT(VARCHAR,@sensorId_2) +
    ' FROM [SensorData] 
      WHERE sensorId IN (' + CONVERT(VARCHAR,@sensorId_1) + ', ' + CONVERT(VARCHAR,@sensorId_2) + ') ' +
    ' AND [date] >= ' + QUOTENAME(CONVERT(VARCHAR,@startDateTime,120),'''') +
    ' AND [date] < ' + QUOTENAME(CONVERT(VARCHAR,@endDateTime,120),'''') +
    ' GROUP BY CAST([date] AS DATE)
      ORDER BY CAST([date] AS DATE)'
    
    EXEC sp_executesql @sql
    

    对于每小时的细分,我只需更改 @sql 定义:

    SET @sql =
    'SELECT CONVERT(VARCHAR,CAST([date] AS DATE)) + '' '' + CONVERT(VARCHAR,DATEPART(HOUR,[date])) + '':00'' AS [Hour], 
            SUM(CASE WHEN sensorId = ' + CONVERT(VARCHAR,@sensorId_1) + ' THEN 1 ELSE 0 END) AS Sensor_' + CONVERT(VARCHAR,@sensorId_1) + ',' +
          ' SUM(CASE WHEN sensorId = ' + CONVERT(VARCHAR,@sensorId_2) + ' THEN 1 ELSE 0 END) AS Sensor_' + CONVERT(VARCHAR,@sensorId_2) +
    ' FROM [SensorData] 
      WHERE sensorId IN (' + CONVERT(VARCHAR,@sensorId_1) + ', ' + CONVERT(VARCHAR,@sensorId_2) + ') ' +
    ' AND [date] >= ' + QUOTENAME(CONVERT(VARCHAR,@startDateTime,120),'''') +
    ' AND [date] < ' + QUOTENAME(CONVERT(VARCHAR,@endDateTime,120),'''') +
    ' GROUP BY CONVERT(VARCHAR,CAST([date] AS DATE)) + '' '' + CONVERT(VARCHAR,DATEPART(HOUR,[date])) + '':00''
      ORDER BY CONVERT(VARCHAR,CAST([date] AS DATE)) + '' '' + CONVERT(VARCHAR,DATEPART(HOUR,[date])) + '':00'''
    

    如果您希望能够动态指定时间间隔(分钟、日、月等)以及希望在每个“存储桶”中包含多少个该时间间隔的单位,那么您需要将其设为更复杂一点。

    我会有一个CASE 语句来确定动态 SQL 是如何构建的,具体取决于(可能相当有限?)您可能想要处理的不同间隔集,但我不熟悉 PIVOT,所以也许这可以为您提供更优雅的解决方案。

    无论如何,希望对GROUP BY 部分有所帮助,如果我完全错过了重点并且您已经理解了它的这个元素,请原谅!

    【讨论】:

      【解决方案2】:

      您希望它在sensorID 上旋转,但按intervalAmount * datediff(intervalTime, startDateTime, endDateTime) 分组?

      对于group by,试试:

      select
        sensorID,
        @intervalAmount * datediff(@intervalTime, @startDateTime, @endDateTime) as timeSpanGroup,
        count(*)
      from
        tbl
      where
        date >= @startDateTime and
        date <= @endDateTime and
        sensorId in (@sensorID_1, @sensorID_2)
      group by
        sensorID, @intervalAmount * datediff(@intervalTime, @startDateTime, @endDateTime)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-03
        • 2021-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-10
        • 2012-02-18
        相关资源
        最近更新 更多