【问题标题】:How can I join multiple tables with same primary key to one table with one row per key?如何将具有相同主键的多个表连接到每个键一行的表中?
【发布时间】:2021-07-21 11:03:04
【问题描述】:

我有什么

我有多个带有主键 key 和值的表。每个键可能存在于所有表中,也可能只存在于表的子集中。

以下是示例表:

表 1:

key value
A 1
C 3

Tab2:

key value
A 10
D 10

Tab3:

key value
B 20
D 10

我想要什么

我想以这样一种方式加入表格,即每个现有键获得一行,每个表格获得一列。如果其中一个表中不存在键,则应假定为null。所以对于上面的例子,我想得到这个结果:

key tab1 tab2 tab3
A 1 10 NULL
B NULL NULL 20
C 3 NULL NULL
D NULL 10 10

到目前为止我尝试过的内容

这是我想出的,可行的:

with tab1 as (
    select * from (values('A', 1), ('C', 3))x(key, value)
),
tab2 as (
    select * from (values('A', 10), ('D', 10))x(key, value)
),
tab3 as (
    select * from (values('B', 20), ('D', 10))x(key, value)
)
select
    coalesce(tab1.key, tab2.key, tab3.key) "key",
    tab1.value tab1,
    tab2.value tab2,
    tab3.value tab3
from tab1
full outer join tab2 on tab2.key = tab1.key
full outer join tab3 on tab3.key = coalesce(tab1.key, tab2.key)
order by coalesce(tab1.key, tab2.key, tab3.key)

问题

在上面的情况下,我的查询看起来还不错,但是在实际情况下,我需要连接 6 个表,并且键实际上分布在三列中。这会导致很长的连接语句。第六个表的语句如下所示:

full outer join tab6
    on tab6.key1 = coalesce(tab1.key1, tab2.key1, tab3.key1, tab4.key1, tab5.key1)
    and tab6.key2 = coalesce(tab1.key2, tab2.key2, tab3.key2, tab4.key2, tab5.key2)
    and tab6.key3 = coalesce(tab1.key3, tab2.key3, tab3.key3, tab4.key3, tab5.key3)

从代码质量的角度来看,复制和粘贴coalesce-calls 的激增有些令人不安。

还有其他更简单的方法可以获得我想要的结果吗?

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    使用FULL JOIN .. USING

    SELECT key, t1.value AS tab1, t2.value AS tab2, t3.value AS tab3
    FROM t1
    FULL JOIN t2 USING (key)
    FULL JOIN t3 USING (key)
    

    dbfiddle

    【讨论】:

      【解决方案2】:

      3张桌子的解决方案

      WITH keys AS (
          SELECT key FROM tab1 UNION
          SELECT key FROM tab2 UNION
          SELECT key FROM tab3 
      )
      SELECT key, t1.value, t2.value, t3.value
      FROM keys AS k
      LEFT JOIN tab1 AS t1 USING (key)
      LEFT JOIN tab2 AS t2 USING (key)
      LEFT JOIN tab3 AS t3 USING (key)
      

      对于下一个表,只需将其添加到 CTE keys 即可从所有表中获取所有出现的键。然后将此表附加到此 CT​​E 以获取值。

      对于 10 个表,它仍然相当紧凑和合乎逻辑,最重要的是,添加更多表很容易:

      WITH keys AS (
          SELECT key FROM tab1 UNION
          SELECT key FROM tab2 UNION
          SELECT key FROM tab3 UNION
          SELECT key FROM tab4 UNION
          SELECT key FROM tab5 UNION
          SELECT key FROM tab6 UNION
          SELECT key FROM tab7 UNION
          SELECT key FROM tab8 UNION
          SELECT key FROM tab9 UNION
          SELECT key FROM tab10  
      )
      SELECT 
          key, 
          t1.value, t2.value, t3.value, t4.value, t5.value, t6.value, t7.value, t8.value, t9.value, t10.value
      FROM keys AS k
      LEFT JOIN tab1 AS t1 USING (key)
      LEFT JOIN tab2 AS t2 USING (key)
      LEFT JOIN tab3 AS t3 USING (key)
      LEFT JOIN tab4 AS t4 USING (key)
      LEFT JOIN tab5 AS t5 USING (key)
      LEFT JOIN tab6 AS t6 USING (key)
      LEFT JOIN tab7 AS t7 USING (key)
      LEFT JOIN tab8 AS t8 USING (key)
      LEFT JOIN tab9 AS t9 USING (key)
      LEFT JOIN tab10 AS t10 USING (key)
      

      有一个小提琴: https://www.db-fiddle.com/f/9aa2wUtR2RbQaGKTtXrr1W/1

      或者当你可以获取所有键和连接值时创建一个视图,或者使用 FULL JOIN(参见 Lukas 的解决方案)

      【讨论】:

        【解决方案3】:
        select key1, key2, key3,
               tab1.value as value1,
               tab2.value as value2,
               tab3.value as value3,
               tab4.value as value4,
               tab5.value as value5,
               tab6.value as value6
        from tab1 full join
             tab2
             using (key1, key2, key3) full join
             tab3
             using (key1, key2, key3) full join
             tab4
             using (key1, key2, key3) full join
             tab5
             using (key1, key2, key3) full join
             tab6
             using (key1, key2, key3);
        

        如果另一个值可用,using 子句将忽略 NULLs 的键值,因此不需要复杂的 coalesce() 表达式。然后,您可以在查询的其他地方引用键值(不带表别名)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-15
          • 1970-01-01
          • 2022-10-03
          • 1970-01-01
          • 1970-01-01
          • 2011-11-11
          相关资源
          最近更新 更多