2016-10-11 39 views
0

我遇到了一個postgres查詢的奇怪問題。除了一個非常特定的場景外,查詢可以在多種情況下使用各種其他分組,總和等方式正常工作。Postgres:使用Case和Group By時需要的聚合函數,但僅在使用連接時

下面的代碼是從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 

我得到的錯誤如下:錯誤:列「fsp.stageonecompletetime」必須出現在GROUP BY子句中或用於聚合函數中。

現在,我不明白爲什麼我得到這個錯誤,只有當我與用戶表進行連接時才返回。

任何幫助將不勝感激。

+1

不知道它是否會有所幫助,因爲我在Oracle SQL環境中工作,但在那裏您不能只將狀態放入組中,您必須在子句時刪除整個案例。你嘗試過嗎? –

+0

你能解釋一下'TO_TIMESTAMP'在這裏做什麼嗎?創建的時間是否以字符串形式存儲?如果是這樣,以什麼格式?並不'降低(用戶名)='測試'看起來很有趣? –

+0

嘿,是的,'測試'是我的錯(因爲我在提交這個問題時改變了實際的用戶名),我忘記了它更低。 – bigad1992

回答

1

我懷疑你的users表中有一個名爲status的列,這已經改變了組的語義,所以它不再引用別名的case表達式。

嘗試更改您使用的別名。

+0

謝謝,我相信這可能是問題,因爲我在用戶表中有一個狀態列。我最終通過取出子查詢中的聚合函數和分組,最終以不同的方式修復它,而是按原樣返回每一行,然後僅在主查詢中進行聚合和分組。 – bigad1992

+0

@David Aldridge:這看起來很可能。此外,這表明最好不要在'GROUP BY'中使用別名,因爲如果現在使用別名'state'而不是'status',則只有在沒有人向其中添加列'state'的情況下,查詢纔會運行的表格:-)如果完全使用別名,應該使用一些命名約定,以避免具有別名和列的相同名稱。 –

+0

@ bigad1992:聽起來不錯。當使用所有表格時,人們可以簡單地將所有表格聯合起來並在整體上工作。 –

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子句移到單表查詢中。正如查詢更具可讀性和可維護性。

相關問題