簡體   English   中英

PostgreSQL:分組然后過濾表,條件為不存在

[英]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    ║
╚═══╩═══╩══════╝

......這樣:

  1. 輸入表的行按A和B分組
  2. 對於每個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表達式, FALSETRUE之前排序。 如果可以有多行,請添加更多ORDER BY項以斷開關系。

CASE WHEN A = C THEN D END實現了您的要求, D僅在給定條件下輸出。 否則,我們會根據需要獲得NULLCASE的默認值)。

詳細說明:

大表可能會進行更多性能優化:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM