如何在SQL中将多天的值组合成一个月?

时间:2018-11-27 18:10:31

标签: sql sql-server tsql

我有许多处于各种状态的设备(本质上是“正在运行”或“关闭”,但还有其他状态)。每天结束时都会拍摄快照,以记录设备处于什么状态。我将COUNT个设备汇总为总体“正在运行”或“关闭”(例如,01月1日-726台CCTV正在“运行”)在01-01-18上有18台和4台CCTV处于“关闭”状态,在01-02-18上有728台CCTV正在“运行”,而在01-02-18上有2部CCTV在“下降”状态,等等。)

这是我当前的代码:

SELECT oper.failurecode AS 'Device Type', 
       COUNT(hist.status) AS 'Count', 
       hist.status AS 'Status', 
       CONVERT(DATE, DATEADD(MINUTE, -30, hist.datadatetime)) AS 'Date'
FROM locations loc
        INNER JOIN locoper oper ON oper.location = loc.location
        INNER JOIN serclochistory hist ON hist.location = loc.location
WHERE hist.status NOT IN ('DECOMMISSIONED', 'TRANSITION', 'NOT READY', 'NOT READY - Fiber') 
  AND CONVERT(TIME, hist.datadatetime) > '23:00:00'
GROUP BY 
    CONVERT(DATE, DATEADD(MINUTE, -30, hist.datadatetime)), 
    oper.failurecode, 
    hist.status
ORDER BY 
    CONVERT(DATE, DATEADD(MINUTE, -30, hist.datadatetime)), 
    oper.failurecode, 
    hist.status;

这给了我如下结果:

CCTV   6    DOWN       2018-01-01
CCTV   763  OPERATING  2018-01-01
CCTV   18   DOWN       2018-01-02
CCTV   748  OPERATING  2018-01-02

我想做的是合并该月的所有设备,以便看到如下结果:

CCTV   24   DOWN       2018-01
CCTV   1511 OPERATING  2018-01

我可以找到一些示例,这些示例说明如何将项目组合到一行,但不能以这种方式添加值。

2 个答案:

答案 0 :(得分:0)

您的查询建议使用SQL Server语法,则可以:

SELECT oper.failurecode AS 'Device Type', COUNT(hist.status) AS 'Count', hist.status AS 'Status', CONVERT(DATE, DATEADD(MINUTE, -30, hist.datadatetime)) AS 'Date'
FROM locations loc INNER JOIN 
     locoper oper 
     ON oper.location = loc.location INNER JOIN 
     serclochistory hist 
     ON hist.location = loc.location
WHERE hist.status NOT IN ('DECOMMISSIONED', 'TRANSITION', 'NOT READY', 'NOT READY - Fiber') AND CONVERT(TIME, hist.datadatetime) > '23:00:00'
GROUP BY CONVERT(VARCHAR(7), DATEADD(MINUTE, -30, hist.datadatetime), 120), oper.failurecode, hist.status
ORDER BY Date, oper.failurecode, hist.status;

答案 1 :(得分:0)

我很想使用通用表表达式(CTE)进行初始数据捕获。这样,您只需要转换一次日期值。阅读您的分组和排序也更加容易。

我不清楚是否需要从日期值中减去30分钟,但我认为其目的是捕获午夜30分钟左右的状态记录。您发布的查询不会执行此操作,因为时间过滤器未处于调整后的值。

无论如何-试一试。希望对您有所帮助。

;WITH statusFilteredRecords ([Device Type], [Status], [Date])
-- Set of records filtered by status, with the time adjustment of -30 minutes applied to the date.
AS
(
    SELECT      oper.failurecode AS 'Device Type', 
                hist.status AS 'Status', 
                DateAdd(MINUTE, -30, hist.dateadatetime) [Date] -- This normalises "End of Day" as being midnight +/- 30 minutes
    FROM        locations loc
    INNER JOIN  locoper oper 
            ON  oper.location = loc.location
    INNER JOIN  serclochistory hist 
            ON  hist.location = loc.location
    WHERE       hist.status NOT IN ('DECOMMISSIONED', 'TRANSITION', 'NOT READY', 'NOT READY - Fiber')       
)
, eodFilteredRecords ([Device Type], [Status], [Date])
-- Set of records filtered by Time, so that only EOD records are included, with the date normalized to the first of the month for grouping
AS  
(
    SELECT  [Device Type],
            [Status],
            CAST(DateAdd(dd, -(day([Date])-1), [Date]) as Date) AS [Date] -- Force the date to the first of the month.
    FROM    statusFilteredRecords
    WHERE   CONVERT(TIME, [Date]) > '23:00:00' -- Because we're operating on the normalized datetime value, this is really > 23:30 or < 00:30
)
SELECT      [Device Type], 
            count([Status]) as [Count],
            [Status], 
            [Date]
FROM        eodFilteredRecords
GROUP BY    [Device Type], 
            [Status], 
            [Date]
ORDER BY    [Date], 
            [Device Type], 
            [Status]

<==编辑:回答OP要求解释的评论==>

Count()是一个聚合函数-它对结果子组中的数据进行操作。 在这种情况下,子组是在[Device Type][Status][Date]上匹配的子组-这是在查询的GROUP BY子句中指定的。

GROUP BY    [Device Type], 
            [Status], 
            [Date]

在原始查询中,GROUP BY子句将字段DateTime中的hist.dateadatetime值转换为Date值(没有时间分量)。删除值的 time 部分意味着给定 day 的所有值现在都相等,并且都属于同一子组。 ({01-Jan-2018 15:22:33变成01-Jan-201801-Jan-2018 22:51:00等)。

GROUP BY 
    CONVERT(DATE, DATEADD(MINUTE, -30, hist.datadatetime)), 
    oper.failurecode, 
    hist.status

我要做的是进一步执行此步骤,以有效删除值的 time 部分和 day 部分,并将所有日期设置为第一个

CAST(DateAdd(dd, -(day([Date])-1), [Date]) as Date) AS [Date]

我们假设日期为2018年9月28日。我使用day([Date])来获取月份中的某天(例如28),然后从该值中减去1(得出27),然后减去该天数,因此它会回到该月的第一天。

因此,现在,当我们评估GROUP BY [Device Type], [Status], [Date]时,我们会将在同一 month 内发生的所有记录归为一组(11-Sep-2018变成01-Sep-201830-Sep-2018等。

将聚合函数Count()应用于这些不太细粒度的记录组(将我的月份而不是日期分组)会得到您要查找的汇总结果。