计算给定日期范围内每天的设备数
Count devices per day in a given date range
我有一个 table 设备有 3 种状态,通过、失败和警告。
Device
Status
Date
Device1
Pass
12/1/2020
Device2
Fail
12/1/2020
Device3
Warning
12/1/2020
Device1
Fail
12/2/2020
Device2
Warning
12/2/2020
Device3
Pass
12/2/2020
我想根据每天的状态生成设备数量的趋势图。每天都在所有设备上进行计数。上面的 table 将在多个日期重复设备数据。
示例:
我想生成一个堆叠条形图,它将显示通过、失败或警告的设备数。需要获取一个查询,我可以使用它来获取响应 DateTime
、失败设备的数量、通过的设备数量、在日期范围内发出警告的设备数量。
select * (select count(*) from status_table where overall_status = 'Fail' and startDate > "" and endDate < "") as failedCount,
(select count(*) from status_table where overall_status = 'Warning' and startDate > "" and endDate < "") as WarningCount,
(select count(*) from status_table where overall_status = 'Pass' startDate > "" and endDate < "") as passCount from status_table
有更好的解决方案吗?
您可以使用聚合 FILTER
子句在单个查询中执行此操作。
这会在选定日期范围内的每一天为每个选定设备获取三个计数(失败、通过、警告)。没有任何出现的天数为 NULL。 0 如果设备出现,但不具有此状态:
SELECT date, device_name
, fail_count, warning_count, pass_count
FROM (SELECT DISTINCT device_name FROM status_table) d -- all devices ①
CROSS JOIN (
SELECT generate_series(timestamp '2020-12-01'
, timestamp '2020-12-31'
, interval '1 day')::date
) t(date) -- all dates
LEFT JOIN (
SELECT date, device_name
, count(*) FILTER (WHERE overall_status = 'Fail') AS fail_count
, count(*) FILTER (WHERE overall_status = 'Warning') AS warning_count
, count(*) FILTER (WHERE overall_status = 'Pass') AS pass_count
FROM status_table
WHERE date >= '2020-12-01' -- same date range as above
AND date <= '2020-12-31'
GROUP BY 1, 2
) s USING (date, device_name)
ORDER BY 1, 2;
基本上,您 CROSS JOIN
所有设备到所有日期(笛卡尔积),附加数据可以在其中找到数据 LEFT JOIN
。
① 由于您似乎没有 device
table(您可能应该有),请即时生成完整列表。上面带有 DISTINCT
的查询适用于每个设备的几行。否则,还有(很多)更快的技术,例如:
WITH RECURSIVE cte AS (
(SELECT device_name FROM status_table ORDER BY 1 LIMIT 1)
UNION ALL
SELECT (SELECT device_name FROM status_table
WHERE device_name > t.device_name ORDER BY 1 LIMIT 1)
FROM cte
WHERE device_name IS NOT NULL
)
SELECT * FROM cte
WHERE device_name IS NOT NULL;
参见:
子查询 s
仅聚合给定日期范围内的行。它是严格可选的。也可以直接left-join到底层的table,然后聚合所有。但是这种方法通常(快得多)。
您可以使用 COALESCE
/ NULLIF
.
将 NULL 转换为零,反之亦然
相关:
PostgreSQL: running count of rows for a query 'by minute'
Aggregate columns with additional (distinct) filters
对于更多标志,crosstab()
查询可能会更快。参见:
- PostgreSQL Crosstab Query
关于生成日期范围:
- Generating time series between two dates in PostgreSQL
请注意,如果您使用 timestamp with time zone
操作,日期将由您当前的时区设置定义。参见:
- Ignoring time zones altogether in Rails and PostgreSQL
我有一个 table 设备有 3 种状态,通过、失败和警告。
Device | Status | Date |
---|---|---|
Device1 | Pass | 12/1/2020 |
Device2 | Fail | 12/1/2020 |
Device3 | Warning | 12/1/2020 |
Device1 | Fail | 12/2/2020 |
Device2 | Warning | 12/2/2020 |
Device3 | Pass | 12/2/2020 |
我想根据每天的状态生成设备数量的趋势图。每天都在所有设备上进行计数。上面的 table 将在多个日期重复设备数据。
示例:
我想生成一个堆叠条形图,它将显示通过、失败或警告的设备数。需要获取一个查询,我可以使用它来获取响应 DateTime
、失败设备的数量、通过的设备数量、在日期范围内发出警告的设备数量。
select * (select count(*) from status_table where overall_status = 'Fail' and startDate > "" and endDate < "") as failedCount,
(select count(*) from status_table where overall_status = 'Warning' and startDate > "" and endDate < "") as WarningCount,
(select count(*) from status_table where overall_status = 'Pass' startDate > "" and endDate < "") as passCount from status_table
有更好的解决方案吗?
您可以使用聚合 FILTER
子句在单个查询中执行此操作。
这会在选定日期范围内的每一天为每个选定设备获取三个计数(失败、通过、警告)。没有任何出现的天数为 NULL。 0 如果设备出现,但不具有此状态:
SELECT date, device_name
, fail_count, warning_count, pass_count
FROM (SELECT DISTINCT device_name FROM status_table) d -- all devices ①
CROSS JOIN (
SELECT generate_series(timestamp '2020-12-01'
, timestamp '2020-12-31'
, interval '1 day')::date
) t(date) -- all dates
LEFT JOIN (
SELECT date, device_name
, count(*) FILTER (WHERE overall_status = 'Fail') AS fail_count
, count(*) FILTER (WHERE overall_status = 'Warning') AS warning_count
, count(*) FILTER (WHERE overall_status = 'Pass') AS pass_count
FROM status_table
WHERE date >= '2020-12-01' -- same date range as above
AND date <= '2020-12-31'
GROUP BY 1, 2
) s USING (date, device_name)
ORDER BY 1, 2;
基本上,您 CROSS JOIN
所有设备到所有日期(笛卡尔积),附加数据可以在其中找到数据 LEFT JOIN
。
① 由于您似乎没有 device
table(您可能应该有),请即时生成完整列表。上面带有 DISTINCT
的查询适用于每个设备的几行。否则,还有(很多)更快的技术,例如:
WITH RECURSIVE cte AS (
(SELECT device_name FROM status_table ORDER BY 1 LIMIT 1)
UNION ALL
SELECT (SELECT device_name FROM status_table
WHERE device_name > t.device_name ORDER BY 1 LIMIT 1)
FROM cte
WHERE device_name IS NOT NULL
)
SELECT * FROM cte
WHERE device_name IS NOT NULL;
参见:
子查询 s
仅聚合给定日期范围内的行。它是严格可选的。也可以直接left-join到底层的table,然后聚合所有。但是这种方法通常(快得多)。
您可以使用 COALESCE
/ NULLIF
.
相关:
PostgreSQL: running count of rows for a query 'by minute'
Aggregate columns with additional (distinct) filters
对于更多标志,crosstab()
查询可能会更快。参见:
- PostgreSQL Crosstab Query
关于生成日期范围:
- Generating time series between two dates in PostgreSQL
请注意,如果您使用 timestamp with time zone
操作,日期将由您当前的时区设置定义。参见:
- Ignoring time zones altogether in Rails and PostgreSQL