【问题标题】:SQL query that is able to count days based on event queries能够根据事件查询计算天数的 SQL 查询
【发布时间】:2023-03-16 15:23:01
【问题描述】:

我发布了这个here,但也决定在这里发布。

我有一个包含以下数据的表格:

id    date_changed                  color_start         color_end
-------------------------------------------------------------------

1     2020-05-27 16:33:52.000       green                yellow
1     2020-06-11 20:12:18.000       yellow               red
1     2020-06-11 20:20:58.000       red                  green
2     2021-03-03 14:31:44.000       yellow               red
2     2020-08-06 14:59:21.000       green                yellow              
3     2021-04-28 12:36:45.000       green                red
...

例如,id #2 的项目在 2020-08-06 14:59:21 从绿色变为黄色,然后在 2021-03-03 14:31:44 从黄色变为读取。我需要计算两个时间范围内有多少项处于绿色、黄色、红色状态。

我通过做一些研究来尝试以下查询,基本上列出过去一年的事件或每天,但这并不是我真正想要的。

SELECT d.date, items.id,
count(CASE WHEN items.color_end = 'yellow' THEN 1 ELSE null END) as yellow_count,
count(CASE WHEN items.color_end = 'green' THEN 1 ELSE null END) as green_count,
count(CASE WHEN items.color_end = 'red' THEN 1 ELSE null END) as red_count,
count(CASE WHEN items.color_end = 'yellow' THEN 1 ELSE null end) + 
count(CASE WHEN items.color_end = 'green' THEN 1 ELSE null END) + 
count(CASE WHEN items.color_end = 'red' THEN 1 ELSE null END) as total_count
FROM (SELECT to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD') AS date 
      FROM generate_series(0, 365, 1) AS offs
     ) d LEFT OUTER JOIN
     events items
     ON d.date = to_char(date_trunc('day', item.date_changed), 'YYYY-MM-DD')
GROUP BY d.date, items.id;

【问题讨论】:

  • 如果您也添加所需的输出将会很有帮助。

标签: sql postgresql count


【解决方案1】:

“我需要计算两个时间范围内有多少项目处于绿色、黄色、红色状态”

首先我们计算与每种颜色和每个 id 关联的时间范围。

SELECT id, color_start AS color
     , tsrange
         ( CASE 
             WHEN first_value(color_end) OVER w IS DISTINCT FROM color_start
             THEN NULL :: timestamp without time zone
             ELSE first_value(date_changed) OVER w
           END
         , CASE 
             WHEN last_value(color_start) OVER w  IS DISTINCT FROM color_end
             THEN NULL :: timestamp without time zone
             ELSE date_changed
           END
         ) AS range
  FROM 
     ( SELECT * 
         FROM your_table
       UNION ALL
       ( SELECT DISTINCT ON (id)
                id, date_changed, color_end, NULL
           FROM your_table
          ORDER BY id, date_changed DESC
       )
     ) AS t
WINDOW w AS (PARTITION BY id ORDER BY date_changed ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)

结果是:

id  color   range
1   green   (,"2020-05-27 16:33:52")
1   yellow  ["2020-05-27 16:33:52","2020-06-11 20:12:18")
1   red     ["2020-06-11 20:12:18","2020-06-11 20:20:58")
1   green   ["2020-06-11 20:20:58",)
2   green   (,"2020-08-06 14:59:21")
2   yellow  ["2020-08-06 14:59:21","2021-03-03 14:31:44")
2   red     ["2021-03-03 14:31:44",)
3   green   (,"2021-04-28 12:36:45")
3   red     ["2021-04-28 12:36:45",)

然后,假设我们想要tsrange('2020-06-01','2021-01-01') 时间范围内每个 id 的颜色数,查询是:

WITH list AS
(
SELECT id, color_start AS color
     , tsrange
         ( CASE 
             WHEN first_value(color_end) OVER w IS DISTINCT FROM color_start
             THEN NULL :: timestamp without time zone
             ELSE first_value(date_changed) OVER w
           END
         , CASE 
             WHEN last_value(color_start) OVER w  IS DISTINCT FROM color_end
             THEN NULL :: timestamp without time zone
             ELSE date_changed
           END
         ) AS range
  FROM 
     ( SELECT * 
         FROM your_table
       UNION ALL
       ( SELECT DISTINCT ON (id)
                id, date_changed, color_end, NULL
           FROM your_table
          ORDER BY id, date_changed DESC
       )
     ) AS t
WINDOW w AS (PARTITION BY id ORDER BY date_changed ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
)
SELECT id, count(*)
  FROM list
 WHERE range && tsrange('2020-06-01','2021-01-01')
 GROUP BY id

结果是:

id  count
1   3
2   2
3   1

dbfiddle中的测试结果

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 2019-05-29
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 2015-10-31
    相关资源
    最近更新 更多