1

在 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) 行。

我想不出任何方法来使用聚合函数窗口函数子查询来执行这种转换。

4

2 回答 2

2

使用返回所有行的 CTEA = 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   |
于 2019-07-24T14:01:58.850 回答
1

要从每个组中获取相同的单行,(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)。

详细解释:

大表可能会进行更多的性能优化:

于 2019-07-24T16:54:24.453 回答