Postgresql
為每個選擇具有不同條件的多行
我正在嘗試組合一個查詢將返回多個日期範圍內的銷售資訊。我打算做這樣的事情:
SELECT count(*) AS thirty_day_sales FROM "MySchema"."MyTable" MT WHERE MT.date > now()::date - interval '30 days' UNION SELECT count(*) AS sixty_day_sales FROM "MySchema"."MyTable" MT WHERE MT.date > now()::date - interval '60 days' UNION SELECT count(*) AS ninety_day_sales FROM "MySchema"."MyTable" MT WHERE MT.date > now()::date - interval '90 days'
有沒有另一種更有效的方法來做到這一點
UNION
?我不想一遍又一遍地重複SELECT
和WHERE
行,因為實際的標準要長得多,而且比這更複雜,多個表連接在一起。
這將返回數據透視。它可能會也可能不會更快。
SELECT count(*) AS '90 days', count(*) FILTER (WHERE mt.date > now()::date - interval '60 days') AS '60 days' count(*) FILTER (WHERE mt.date > now()::date - interval '30 days') AS '30 days' FROM "MySchema"."MyTable" AS mt WHERE mt.date > now()::date - interval '90 days';
如果需要在一列中返回計數結果,這是一種避免聯合的方法。
首先,用代表日期所在儲存桶的值標記每一行(0 到 30 天的儲存桶為 30,30 到 60 天的儲存桶為 60,60 到 90 的儲存桶為 90):
SELECT ... FROM "MySchema"."MyTable" AS mt CROSS JOIN LATERAL ( SELECT CASE WHEN mt.date > now()::date - interval '30 days' THEN 30 WHEN mt.date > now()::date - interval '60 days' THEN 60 ELSE 90 END ) AS x (PeriodLength) WHERE mt.date > now()::date - interval '90 days' ;
以上將為您提供這樣的數據集:
*some columns* PeriodLength ------------ ------------ *some values* 90 ... 90 ... ... ... 60 ... 60 ... ... ... 30 ... 30 ... ...
您現在可以分組
PeriodLength
併計算每個組中的行數:SELECT x.PeriodLength, COUNT(*) AS BucketCount FROM "MySchema"."MyTable" AS mt CROSS JOIN LATERAL ( SELECT CASE WHEN mt.date > now()::date - interval '30 days' THEN 30 WHEN mt.date > now()::date - interval '60 days' THEN 60 ELSE 90 END ) AS x (PeriodLength) WHERE mt.date > now()::date - interval '90 days' GROUP BY x.PeriodLength ;
這會給你一個這樣的輸出(為了一個例子顯示任意數字):
PeriodLength BucketCount ------------ ----------- 90 45 60 30 30 35
但是,當您希望從現在開始計算期間的計數時,結果將適用於儲存桶。因此,最後一步應該是按 的升序獲取計數的總和
PeriodLength
,如下所示:SELECT x.PeriodLength, SUM(COUNT(*)) OVER (ORDER BY x.PeriodLength ASC) AS BucketCount FROM "MySchema"."MyTable" AS mt CROSS JOIN LATERAL ( SELECT CASE WHEN mt.date > now()::date - interval '30 days' THEN 30 WHEN mt.date > now()::date - interval '60 days' THEN 60 ELSE 90 END ) AS x (PeriodLength) WHERE mt.date > now()::date - interval '90 days' GROUP BY x.PeriodLength ;
現在結果將如下所示(基於之前的輸出):
PeriodLength BucketCount ------------ ----------- 90 110 60 65 30 35
如果您在 SELECT 語句本身上省略 ORDER BY,則這些行可能會以不同的順序返回,但數字仍將與各自的周期長度匹配。
如果您更喜歡適當的標籤,例如
90 days
而不是 just90
,您可以進一步格式化 的輸出PeriodLength
,例如:SELECT x.PeriodLength || ' days' AS PeriodLength, ...
我只想建議您僅對輸出執行此操作,而不是在 CASE 表達式計算中執行此操作
x.PeriodLength
。保持 CASE 結果為數字,以便您可以使用它們進行排序,並在盡可能高的級別格式化它們(最好在客戶端中,但如果您必須在 SQL 中執行,則讓它成為最頂層)。