我的一个postgres查询有一个奇怪的问题。除了一个非常具体的场景之外,该查询在多种场景中可以正常工作,包括各种其他分组,总和等。
下面的代码是计算来自5个不同表的行(忽略这个本身就是哑,这是一个非常糟糕和讨厌的数据库结构的事实)并根据CASE函数中返回的值对它们进行分组。它如下工作正常:
SELECT SUM(count) as count, status FROM
(SELECT count(fsp.id) as count, CASE WHEN fsp.stageonecompletetime = 0 THEN 'in-progress'
WHEN fsp.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN fsp.completedtime = 0 THEN 'awaiting-authorisation'
WHEN fsp.senttodate = 0 THEN 'awaiting-distribution'
WHEN fsp.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.fleet_solution_policy fsp WHERE TO_TIMESTAMP(fsp.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(fsp.createdtime) < '2016-10-03' GROUP BY status
UNION ALL
SELECT count(cba.id) as count, CASE WHEN cba.stageonecompletetime = 0 THEN 'in-progress'
WHEN cba.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN cba.completedtime = 0 THEN 'awaiting-authorisation'
WHEN cba.senttodate = 0 THEN 'awaiting-distribution'
WHEN cba.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.casing_buyback_agreement cba WHERE TO_TIMESTAMP(cba.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(cba.createdtime) < '2016-10-03' GROUP BY status
UNION ALL
SELECT count(ftp.id) as count, CASE WHEN ftp.stageonecompletetime = 0 THEN 'in-progress'
WHEN ftp.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN ftp.completedtime = 0 THEN 'awaiting-authorisation'
WHEN ftp.senttodate = 0 THEN 'awaiting-distribution'
WHEN ftp.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.fleet_tyre_policy ftp WHERE TO_TIMESTAMP(ftp.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(ftp.createdtime) < '2016-10-03' GROUP BY status
UNION ALL
SELECT count(ds.id) as count, CASE WHEN ds.stageonecompletetime = 0 THEN 'in-progress'
WHEN ds.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN ds.completedtime = 0 THEN 'awaiting-authorisation'
WHEN ds.senttodate = 0 THEN 'awaiting-distribution'
WHEN ds.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.dealer_sla ds WHERE TO_TIMESTAMP(ds.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(ds.createdtime) < '2016-10-03' GROUP BY status
UNION ALL
SELECT count(cg.id) as count, CASE WHEN cg.stageonecompletetime = 0 THEN 'in-progress'
WHEN cg.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN cg.completedtime = 0 THEN 'awaiting-authorisation'
WHEN cg.senttodate = 0 THEN 'awaiting-distribution'
WHEN cg.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.casing_grid cg WHERE TO_TIMESTAMP(cg.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(cg.createdtime) < '2016-10-03' GROUP BY status) allDocuments
GROUP BY status
但是当我必须在查询中加入以允许我按用户过滤结果时,如下所示我得到一个恼人的错误:
SELECT SUM(count) as count, status FROM
(SELECT count(fsp.id) as count, CASE WHEN fsp.stageonecompletetime = 0 THEN 'in-progress'
WHEN fsp.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN fsp.completedtime = 0 THEN 'awaiting-authorisation'
WHEN fsp.senttodate = 0 THEN 'awaiting-distribution'
WHEN fsp.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.fleet_solution_policy fsp JOIN users u1 ON u1.id = fsp.user_id WHERE TO_TIMESTAMP(fsp.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(fsp.createdtime) < '2016-10-03' AND lower(u1.username) = 'Test' GROUP BY status
UNION ALL
SELECT count(cba.id) as count, CASE WHEN cba.stageonecompletetime = 0 THEN 'in-progress'
WHEN cba.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN cba.completedtime = 0 THEN 'awaiting-authorisation'
WHEN cba.senttodate = 0 THEN 'awaiting-distribution'
WHEN cba.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.casing_buyback_agreement cba JOIN users u4 ON u4.id = cba.user_id WHERE TO_TIMESTAMP(cba.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(cba.createdtime) < '2016-10-03' AND lower(u4.username) = 'Test' GROUP BY status
UNION ALL
SELECT count(ftp.id) as count, CASE WHEN ftp.stageonecompletetime = 0 THEN 'in-progress'
WHEN ftp.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN ftp.completedtime = 0 THEN 'awaiting-authorisation'
WHEN ftp.senttodate = 0 THEN 'awaiting-distribution'
WHEN ftp.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.fleet_tyre_policy ftp JOIN users u2 ON u2.id = ftp.user_id WHERE TO_TIMESTAMP(ftp.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(ftp.createdtime) < '2016-10-03' AND lower(u2.username) = 'Test' GROUP BY status
UNION ALL
SELECT count(ds.id) as count, CASE WHEN ds.stageonecompletetime = 0 THEN 'in-progress'
WHEN ds.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN ds.completedtime = 0 THEN 'awaiting-authorisation'
WHEN ds.senttodate = 0 THEN 'awaiting-distribution'
WHEN ds.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.dealer_sla ds JOIN users u3 ON u3.id = ds.user_id WHERE TO_TIMESTAMP(ds.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(ds.createdtime) < '2016-10-03' AND lower(u3.username) = 'Test' GROUP BY status
UNION ALL
SELECT count(cg.id) as count, CASE WHEN cg.stageonecompletetime = 0 THEN 'in-progress'
WHEN cg.stagetwocompletetime = 0 THEN 'awaiting-final-review'
WHEN cg.completedtime = 0 THEN 'awaiting-authorisation'
WHEN cg.senttodate = 0 THEN 'awaiting-distribution'
WHEN cg.senttodate > 0 AND superseded = 0 THEN 'completed'
ELSE 'archived' END AS status FROM fleet_documents.casing_grid cg JOIN users u5 ON u5.id = cg.user_id WHERE TO_TIMESTAMP(cg.createdtime) >= '2016-09-03' AND TO_TIMESTAMP(cg.createdtime) < '2016-10-03' AND lower(u5.username) = 'Test' GROUP BY status) allDocuments
GROUP BY status
我得到的错误如下:错误:列&#34; fsp.stageonecompletetime&#34;必须出现在GROUP BY子句中或用于聚合函数。
现在,我无法理解为什么只有在使用用户表进行连接时才会返回此错误。
非常感谢任何帮助。
答案 0 :(得分:1)
我怀疑你的users表中有一个名为status的列,这改变了组的语义,所以它不再引用别名case表达式。
尝试更改您正在使用的别名。
答案 1 :(得分:1)
这不是真正的答案。 David Aldridge已经给出了正确的答案。
以下是我将如何编写查询。我根本不会加入用户。我会首先将所有表格粘在一起,然后使用它们,就好像它们只是一张桌子一样。我在子查询中对数据进行分类,然后在主查询中使用创建的别名。
select count(*), status
from
(
select
case
when stageonecompletetime = 0 then 'in-progress'
when stagetwocompletetime = 0 then 'awaiting-final-review'
when completedtime = 0 then 'awaiting-authorisation'
when senttodate = 0 then 'awaiting-distribution'
when senttodate > 0 and superseded = 0 then 'completed'
else 'archived'
end as status
from
(
select user_id, createdtime, stageonecompletetime, stagetwocompletetime, completedtime, senttodate, superseded from fleet_documents.fleet_solution_policy
union all
select user_id, createdtime, stageonecompletetime, stagetwocompletetime, completedtime, senttodate, superseded from fleet_documents.casing_buyback_agreement
union all
select user_id, createdtime, stageonecompletetime, stagetwocompletetime, completedtime, senttodate, superseded from fleet_documents.fleet_tyre_policy
union all
select user_id, createdtime, stageonecompletetime, stagetwocompletetime, completedtime, senttodate, superseded from fleet_documents.dealer_sla
union all
select user_id, createdtime, stageonecompletetime, stagetwocompletetime, completedtime, senttodate, superseded from fleet_documents.casing_grid
) data
) classified
where createdtime >= '2016-09-03'
and createdtime < '2016-10-03'
and user_id in (select id from users where lower(username) = 'test')
group by status
order by count(*);
只有当速度太慢时才会将WHERE
子句移动到单表查询中。因为查询更具可读性和可维护性。