[英]PostgreSQL: Grouping then filtering table, with condition for nonexistence
在PostgreSQL中,我有一個表,抽象地看起來像這樣:
╔═══╦═══╦═══╦═══╗
║ A ║ B ║ C ║ D ║
╠═══╬═══╬═══╬═══╣
║ x ║ 0 ║ y ║ 0 ║
║ x ║ 0 ║ x ║ 1 ║
║ x ║ 1 ║ y ║ 0 ║
║ x ║ 1 ║ z ║ 1 ║
║ y ║ 0 ║ z ║ 0 ║
║ y ║ 0 ║ x ║ 0 ║
║ y ║ 1 ║ y ║ 0 ║
╚═══╩═══╩═══╩═══╝
我想在查詢中將其轉換為:
╔═══╦═══╦══════╗
║ A ║ B ║ D ║
╠═══╬═══╬══════╣
║ x ║ 0 ║ 1 ║
║ x ║ 1 ║ null ║
║ y ║ 0 ║ null ║
║ y ║ 1 ║ 0 ║
╚═══╩═══╩══════╝
......這樣:
對於每個A和B對:
如果輸入表具有A = C的任何行,則輸出表具有行(A,B,D),其中D來自A = C的同一行。
例如,輸入表有一行(x,0,x,1),其中A和C都是x。 這意味着輸出表有一行(x,0,1),因為D是1.(x,0,y,0)行(因為它也有A = x和B = 0)被丟棄。
否則,如果不存在這樣的行,則輸出表有一行(A,B,null)。
例如,輸入表有兩行,其中A = y,B = 0-它們是(y,0,z,0)和(y,0,x,0)。 在這些行中都沒有A = C.這意味着輸出表具有(y,0,null)行。
使用CTE返回A = C
所有行並連接到表:
with cte as (
select * from tablename
where "A" = "C"
)
select distinct t."A", t."B", c."D"
from tablename t left join cte c
on c."A" = t."A" and c."B" = t."B"
order by t."A", t."B"
看演示 。
結果:
| A | B | D |
| --- | --- | --- |
| x | 0 | 1 |
| x | 1 | |
| y | 0 | |
| y | 1 | 0 |
要從每個組中獲取具有相同(A, B)
單行,有一種簡單,簡短和快速的方法: DISTINCT ON
- 根本不涉及聚合函數,窗口函數或子查詢:
SELECT DISTINCT ON (A, B)
A, B, CASE WHEN A = C THEN D END AS D
FROM tbl
ORDER BY A, B, (A = C) DESC;
准確地產生您想要的結果。
db <> 在這里小提琴
假設所有涉及的列都定義為NOT NULL
,或者您需要執行更多操作。
最終的ORDER BY
項(A = C) DESC
每行首先對A = C
排序。 它是一個boolean
表達式, FALSE
在TRUE
之前排序。 如果可以有多行,請添加更多ORDER BY
項以斷開關系。
CASE WHEN A = C THEN D END
實現了您的要求, D
僅在給定條件下輸出。 否則,我們會根據需要獲得NULL
( CASE
的默認值)。
詳細說明:
大表可能會進行更多性能優化:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.