确定 COALESCE 字段的来源

Determine source on COALESCE fields

我有两个表 table,它们的结构相同但属于不同的模式(模式 AB)。所有有问题的行将始终出现在 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 结构。
  • 同一查询适用于 ab 中任意数量的列。
  • 即使列名不同,查询也能正常工作。只有列的数量和数据类型必须匹配。 当然,您也可以随时列出选定的兼容列:

    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 NULLb[=64= 中没有匹配 id 的行].因此,任何结果列(id 除外)的来源仍然可以是 'A',即使结果行显示 'B' - 如果 b 中的任何相关列可以是 NULL.
    如果该行存在,我的替代 returns all 值来自 b - 包括 NULL 值。因此,如果 b 中的列可以是 NULL,结果可能会有所不同。哪种行为是可取的取决于您的要求。

任一查询都假定 id 被定义为主键(因此每个给定的 id 值正好是 1 或 0 行)。

相关: