确定 COALESCE 字段的来源
Determine source on COALESCE fields
我有两个表 table
,它们的结构相同但属于不同的模式(模式 A
和 B
)。所有有问题的行将始终出现在 A.table
中,但可能会或可能不会出现在 B.table
中。 B.table
本质上是对 A.table
.
中默认值的覆盖
因此我的查询在每个字段上使用 COALESCE 类似于:
SELECT COALESCE(B.id, A.id) as id,
COALESCE(B.foo, A.foo) as foo,
COALESCE(B.bar, A.bar) as bar
FROM A.table LEFT JOIN B.table ON (A.id = B.id)
WHERE A.id in (1, 2, 3)
效果很好,但我还想添加数据源。在上面的示例中,假设 id=2
存在于 B.table
而不是 1 或 3,我想包括一些指示,表明 A 是 1 和 3 的来源,B 是 2 的来源。
因此数据可能如下所示
+---------------------------------+
| id | foo | bar | source |
+---------------------------------+
| 1 | a | b | A |
| 2 | c | d | B |
| 3 | e | f | A |
+---------------------------------+
我真的不在乎source的值是什么,只要我能区分A和B。
我不是 pgsql 专家(远不是),但我已经对 EXISTS 和子查询进行了修补,但到目前为止运气不佳。
由于显示默认值(来自 A.table)的记录在 B.id 中有 NULL,您只需将此列规范添加到您的查询中:
CASE WHEN B.id IS NULL THEN 'A' ELSE 'B' END AS Source
USING
子句将简化您的查询:
SELECT <b>id</b>
, COALESCE(B.foo, A.foo) AS foo
, COALESCE(B.bar, A.bar) AS bar
, CASE WHEN b.id IS NULL THEN 'A' ELSE 'B' END AS source -- like @Terje provided
FROM a
LEFT JOIN b <b>USING (id)</b>
WHERE a.id IN (1, 2, 3);
但通常情况下,这个替代查询应该能更好地为您服务:
SELECT x.* -- or list columns of your choice
FROM (VALUES (1), (2), (3)) t (id)
, LATERAL (
SELECT *, 'B' AS source FROM b WHERE id = t.id
UNION ALL
SELECT *, 'A' FROM a WHERE id = t.id
LIMIT 1
) x
ORDER BY x.id;
优点:
- 您不必为要添加到结果的每一列都添加另一个
COALESCE
结构。
- 同一查询适用于
a
和 b
中任意数量的列。
即使列名不同,查询也能正常工作。只有列的数量和数据类型必须匹配。
当然,您也可以随时列出选定的兼容列:
SELECT * -- or list columns of your choice
FROM (VALUES (1), (2), (3)) t (id)
, LATERAL (
SELECT <b>foo, bar</b>, 'B' AS source FROM b WHERE id = t.id
UNION ALL
SELECT <b>foo2, bar17</b>, 'A' FROM a WHERE id = t.id
LIMIT 1
) x
ORDER BY x.id;
第一个 SELECT
确定名称、数据类型和列数。
- 如果
b
中的列未定义,则此查询不会中断 NOT NULL
。
COALESCE
无法区分 b.foo IS NULL
和 b
[=64= 中没有匹配 id
的行].因此,任何结果列(id
除外)的来源仍然可以是 'A',即使结果行显示 'B' - 如果 b
中的任何相关列可以是 NULL
.
如果该行存在,我的替代 returns all 值来自 b
- 包括 NULL 值。因此,如果 b
中的列可以是 NULL
,结果可能会有所不同。哪种行为是可取的取决于您的要求。
任一查询都假定 id
被定义为主键(因此每个给定的 id
值正好是 1 或 0 行)。
相关:
我有两个表 table
,它们的结构相同但属于不同的模式(模式 A
和 B
)。所有有问题的行将始终出现在 A.table
中,但可能会或可能不会出现在 B.table
中。 B.table
本质上是对 A.table
.
因此我的查询在每个字段上使用 COALESCE 类似于:
SELECT COALESCE(B.id, A.id) as id,
COALESCE(B.foo, A.foo) as foo,
COALESCE(B.bar, A.bar) as bar
FROM A.table LEFT JOIN B.table ON (A.id = B.id)
WHERE A.id in (1, 2, 3)
效果很好,但我还想添加数据源。在上面的示例中,假设 id=2
存在于 B.table
而不是 1 或 3,我想包括一些指示,表明 A 是 1 和 3 的来源,B 是 2 的来源。
因此数据可能如下所示
+---------------------------------+
| id | foo | bar | source |
+---------------------------------+
| 1 | a | b | A |
| 2 | c | d | B |
| 3 | e | f | A |
+---------------------------------+
我真的不在乎source的值是什么,只要我能区分A和B。
我不是 pgsql 专家(远不是),但我已经对 EXISTS 和子查询进行了修补,但到目前为止运气不佳。
由于显示默认值(来自 A.table)的记录在 B.id 中有 NULL,您只需将此列规范添加到您的查询中:
CASE WHEN B.id IS NULL THEN 'A' ELSE 'B' END AS Source
USING
子句将简化您的查询:
SELECT <b>id</b>
, COALESCE(B.foo, A.foo) AS foo
, COALESCE(B.bar, A.bar) AS bar
, CASE WHEN b.id IS NULL THEN 'A' ELSE 'B' END AS source -- like @Terje provided
FROM a
LEFT JOIN b <b>USING (id)</b>
WHERE a.id IN (1, 2, 3);
但通常情况下,这个替代查询应该能更好地为您服务:
SELECT x.* -- or list columns of your choice
FROM (VALUES (1), (2), (3)) t (id)
, LATERAL (
SELECT *, 'B' AS source FROM b WHERE id = t.id
UNION ALL
SELECT *, 'A' FROM a WHERE id = t.id
LIMIT 1
) x
ORDER BY x.id;
优点:
- 您不必为要添加到结果的每一列都添加另一个
COALESCE
结构。 - 同一查询适用于
a
和b
中任意数量的列。 即使列名不同,查询也能正常工作。只有列的数量和数据类型必须匹配。 当然,您也可以随时列出选定的兼容列:
SELECT * -- or list columns of your choice FROM (VALUES (1), (2), (3)) t (id) , LATERAL ( SELECT <b>foo, bar</b>, 'B' AS source FROM b WHERE id = t.id UNION ALL SELECT <b>foo2, bar17</b>, 'A' FROM a WHERE id = t.id LIMIT 1 ) x ORDER BY x.id;
第一个
SELECT
确定名称、数据类型和列数。- 如果
b
中的列未定义,则此查询不会中断NOT NULL
。
COALESCE
无法区分b.foo IS NULL
和b
[=64= 中没有匹配id
的行].因此,任何结果列(id
除外)的来源仍然可以是 'A',即使结果行显示 'B' - 如果b
中的任何相关列可以是NULL
.
如果该行存在,我的替代 returns all 值来自b
- 包括 NULL 值。因此,如果b
中的列可以是NULL
,结果可能会有所不同。哪种行为是可取的取决于您的要求。
任一查询都假定 id
被定义为主键(因此每个给定的 id
值正好是 1 或 0 行)。
相关: