【问题标题】:Split Date Range and Manipulating Data拆分日期范围和操作数据
【发布时间】:2020-09-03 19:00:46
【问题描述】:

我现在正在处理机器计划项目。我有创建用于记录机器状态的表。在这张表中,我记录了开始和结束状态。现在,如果我输入某个时期之间的日期,我想按该表创建报告。这是我想要的表格和预期结果。

源表:

 machineid |      starttime      |      endtime        |  status | 
-----------+---------------------+---------------------+---------+
   M1      | 2020-01-01 00:00:00 | 2020-01-04 17:00:00 | running |
   M1      | 2020-01-04 17:00:00 | 2020-01-04 18:00:00 | down    |
   M1      | 2020-01-04 18:00:00 | 2020-01-05 14:00:00 | idle    |
   M2      | 2020-01-01 00:00:00 | 2020-01-05 09:00:00 | running |
   M2      | 2020-01-05 09:00:00 | 2020-01-05 18:00:00 | idle    |  

预期结果:

输入开始日期报告:2020-01-01 00:00:00输入结束日期报告:2020-01-05 23:59:59

machineid |    date    | running | idle | down | total |
----------+------------+---------+------+------+-------+
   M1     | 2020-01-01 |    24   |   0  |   0  |   24  |
   M1     | 2020-01-02 |    24   |   0  |   0  |   24  |
   M1     | 2020-01-03 |    24   |   0  |   0  |   24  |
   M1     | 2020-01-04 |    17   |   6  |   1  |   24  |
   M1     | 2020-01-05 |     0   |  14  |   0  |   14  |
   M2     | 2020-01-01 |    24   |   0  |   0  |   24  |
   M2     | 2020-01-02 |    24   |   0  |   0  |   24  |
   M2     | 2020-01-03 |    24   |   0  |   0  |   24  |
   M2     | 2020-01-04 |    24   |   0  |   0  |   24  |
   M2     | 2020-01-05 |     9   |   9  |   0  |   18  |

有什么建议吗?

【问题讨论】:

  • 您需要旋转数据才能将行转换为列
  • 如果我理解你,你想计算特定状态和日期的小时数。我说的对吗?
  • 请向我们展示您的尝试。

标签: sql sql-server database recursive-query


【解决方案1】:

你可以使用CTE:

DECLARE @tmp TABLE(machineid varchar(3), starttime  datetime, endtime datetime,  [status] varchar(20)) 

INSERT INTO @tmp (machineid, starttime, endtime,  [status])
VALUES('M1' , '2020-01-01 00:00:00' , '2020-01-04 17:00:00' , 'running') ,
('M1' , '2020-01-04 17:00:00' , '2020-01-04 18:00:00' , 'down') ,
('M1' , '2020-01-04 18:00:00' , '2020-01-05 14:00:00' , 'idle') ,
('M2' , '2020-01-01 00:00:00' , '2020-01-05 09:00:00' , 'running') ,
('M2' , '2020-01-05 09:00:00' , '2020-01-05 18:00:00' , 'idle')

;WITH CTE AS
(
    --initial data
    SELECT machineid, starttime, endtime, [status]
    FROM @tmp 
    --recursive part
    UNION ALL
    SELECT machineid, DATEADD(HH, 1, starttime) starttime, endtime, [status]
    FROM CTE
    WHERE DATEADD(HH, 1, starttime) < endtime 
)
SELECT machineid, [date], COALESCE([running], 0) [running], COALESCE([idle], 0) [idle], COALESCE([down], 0) [down], COALESCE([running], 0)  + COALESCE([idle], 0) + COALESCE([down], 0) total
FROM
    (
        SELECT machineid, CONVERT(date, starttime) [date], [status], COUNT(starttime) cnt
        FROM CTE
        WHERE CONVERT(date, starttime) BETWEEN '2020-01-01' AND '2020-01-05'
        GROUP BY machineid, CONVERT(date, starttime), [status]
) DT
PIVOT(MAX(cnt) FOR [status] IN ([running], [idle], [down])) PT
ORDER BY machineid, [date]
OPTION (MAXRECURSION 0)

【讨论】:

  • 抱歉回复晚了..感谢@Maciej Los 的回答,这对我有很大帮助,但以防我在记录表之间输入范围之外。总结果可以显示 0 吗?输入开始日期报告:2020-01-01 00:00:00 和输入结束日期报告:2020-01-05 23:59:59` M2 | 2020-01-04 | 24 | 0 | 0 | 24 | M2 | 2020-01-05 | 9 | 9 | 0 | 18 | M2 | 2020-01-06 | 0 | 0 | 0 | 0 | `
  • 在这种情况下,您需要编写另一个查询...然后您必须加入结果。
【解决方案2】:

我同意使用递归 CTE 扩展数据(作为最简单的代码解决方案)。但是,我认为条件聚合比pivot简单得多:

WITH cte AS (
      SELECT machineid, starttime, endtime, status
      FROM t
      UNION ALL
      SELECT machineid, DATEADD(hour, 1, starttime) as starttime, endtime, [status]
      FROM CTE
      WHERE DATEADD(hour, 1, starttime) < endtime 
     )
SELECT machineid, CONVERT(date, starttime) as dte,
       SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) as running,
       SUM(CASE WHEN status = 'idle' THEN 1 ELSE 0 END) as idle,
       SUM(CASE WHEN status = 'down' THEN 1 ELSE 0 END) as down,
       COUNT(*) as total
FROM cte
WHERE starttime >= '2020-01-01' AND 
      starttime < '2020-01-06'
GROUP BY machineid, CONVERT(date, starttime)
ORDER BY machineid, CONVERT(date, starttime)
OPTION (MAXRECURSION 0);

两个音符。首先,这不包括没有活动的日子。您的示例数据并非如此。

其次,这可以提高效率。但是,在您的问题中,性能似乎不是问题。

【讨论】:

  • 我是其中一个答案的作者;)我之前的评论是针对您的解决方案,因为它是我的替代方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
  • 1970-01-01
  • 2020-02-28
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多