如何解决创建一个包含 2 行值的报告,每行值都来自一个单独的 SELECT 语句
我有一个报告(如果您关心的话,使用 Blazer)显示这样的数据,即 jobs
表中最近更新或创建的行的数据:
5 Minutes | 1 Hour | 1 Day | Total
----------------------------------
0 0 367 30,989
SQL 看起来像这样:
SELECT
(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '5 minutes' AND NOW()
) as "5 Minutes",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Hours' AND NOW()
) as "1 Hour",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Day' AND NOW()
) as "1 Day",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
) as "Total"
;
我想为作业 WHERE "Jobs"."active" IS TRUE
添加第二行。我如何让这个显示另一行?
我希望最终的结果是这样的:
Status | 5 Minutes | 1 Hour | 1 Day | Total
-------------------------------------------
* 0 0 367 30,989
Active 0 0 123 24,972
标签不是问题。唯一不明显的是如何创建新行。
解决方法
最简单的方法是在另一组查询上使用 UNION,这些查询具有更严格的 where 子句:
SELECT
'*' as Kind,(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '5 minutes' AND NOW()
) as "5 Minutes",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Hours' AND NOW()
) as "1 Hour",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Day' AND NOW()
) as "1 Day",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
) as "Total"
UNION ALL
SELECT
'Active',(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."IsActive" IS TRUE AND "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '5 minutes' AND NOW()
) as "5 Minutes",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."IsActive" IS TRUE AND "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Hours' AND NOW()
) as "1 Hour",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."IsActive" IS TRUE AND "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Day' AND NOW()
) as "1 Day",(SELECT COUNT(*)
FROM public.jobs AS "Jobs"
WHERE "Jobs"."IsActive" IS TRUE
) as "Total"
,
如果我是你,我更喜欢用这种方式来解决你的问题:
select
"Jobs"."active" as Status,sum(case when "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '5 minutes' AND NOW() then 1 else 0 end) as "5 Minutes",sum(case when "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Hours' AND NOW() then 1 else 0 end) as "1 Hour",sum(case when "Jobs"."updated_at" "Jobs"."updated_at" BETWEEN NOW() - INTERVAL '1 Day' AND NOW() then 1 else 0 end) as "1 Day",count(*) as "Total"
from public.jobs AS "Jobs"
group by "Jobs"."active"
这样您就可以将表格 public.jobs
读取一次,而不是多次(每个 count
一次)。有了这个选择,按 status
分组是一个简单的 group by
操作
基本上,您需要条件聚合。在 Postgres 中,通常使用 filter
:
SELECT COUNT(*) FILTER (WHERE j."updated_at" BETWEEN NOW() - INTERVAL '5 minute' AND NOW()) as cnt_5_minutes,COUNT(*) FILTER (WHERE j."updated_at" BETWEEN NOW() - INTERVAL '1 hour' AND NOW()) as cnt_1_hour,COUNT(*) FILTER (WHERE j."updated_at" BETWEEN NOW() - INTERVAL '1 day' AND NOW()) as cnt_1_day,COUNT(*) as Total
FROM public.jobs j;
您可能没有未来的更新日期,因此可以更简单地写为:
SELECT COUNT(*) FILTER (WHERE j."updated_at" >= NOW() - INTERVAL '5 minute') as cnt_5_minutes,COUNT(*) FILTER (WHERE j."updated_at" >= NOW() - INTERVAL '1 hour') as cnt_1_hour,COUNT(*) FILTER (WHERE j."updated_at" >= NOW() - INTERVAL '1 day') as cnt_1_day,COUNT(*) as Total
FROM public.jobs j;
此外,我建议您去掉 updated_at
中的双引号。在标识符周围使用双引号只是一个坏习惯。
唯一不明显的是如何创建新行。
基本上,用 UNION ALL
添加第二行。
不过,首先要删除每个指标的所有单独的 SELECT
查询。这是不必要的昂贵(如果桌子不是很小很重要)。带有条件聚合的单个 SELECT
可以替换您的所有原始内容(就像 Gordon 建议的那样)。在 Postgres 9.4 或更高版本中,aggregate FILTER
子句 是要走的路。见:
要获得另一行,您可以运行另一个查询,将过滤器 "active" IS TRUE
添加到每个表达式(归结为 active
,因为 boolean
列不需要进一步评估) .
但这会使成本再次翻倍,我们可以避免这种情况。在 CTE 中运行单个 SELECT
,并在外部查询中使用 UNION ALL
进行拆分:
WITH cte AS (
SELECT count(*) FILTER (WHERE updated_at > now() - interval '5 min') AS ct_5min,count(*) FILTER (WHERE updated_at > now() - interval '5 min' AND active) AS ct_5min_a,count(*) FILTER (WHERE updated_at > now() - interval '1 hour') AS ct_1h,count(*) FILTER (WHERE updated_at > now() - interval '1 hour' AND active) AS ct_1h_a,count(*) FILTER (WHERE updated_at > now() - interval '1 day') AS ct_1d,count(*) FILTER (WHERE updated_at > now() - interval '1 day' AND active) AS ct_1d_a,count(*) AS ct_all,count(*) FILTER (WHERE active) AS ct_all_a
FROM public.jobs
)
SELECT '*' AS status,ct_5min,ct_1h,ct_1d,ct_all
FROM cte
UNION ALL
SELECT 'Active',ct_5min_a,ct_1h_a,ct_1d_a,ct_all_a
FROM cte
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。