加入具有不同结构的多个表?

Posted

技术标签:

【中文标题】加入具有不同结构的多个表?【英文标题】:Joining Multiple Tables with different structures? 【发布时间】:2021-05-12 04:39:04 【问题描述】:

我在 SQL 中有一个数据集,其中包含一些需要加入它们的表。有一个主表叫 'main_table' 包含两个参数(id 和 name),其中一个是键 'id'。主表,表A,表B 几乎都有类似的结构,但TableC有点不同,如下:

     main_table:
     id, name,
             01, bb,
             02, cc,
             03, dd,
             04, ff,
             05, gg,

    TableA:
             id, val,
             01, ab,
             03, ac,
             05, ad,
             
    TableB:
             id, val,
             01, ba,
             02, bc,
             04, bd,

    TableC:
             id, val,index
             01, cc, 1
             01, cdf,2
             01, cba,3
             03, ggg,1
             03, dfg,2
             

我可以使用以下查询连接前三个表:

    SELECT main_table.[id],main_table.[name]
           ,TableA.val,TableB.val
     FROM main_table LEFT JOIN TableA ON TableA.id = main_table.id
                     LEFT JOIN TableB ON TableB.id = main_table.id

这给了我下表:

     result_table:
     id, name, val_TA, val_TB
             01, bb  , ab  , ba
             02, cc  , NULL, bc
             03, dd  , ac  , NULL
             04, ff  , NULL, bd
             05, gg  , ad  , NULL
     

但是,当我想以这种方式“左连接”第三个表(TableC)时,它会给我多余的行, 因为 TAbleC 中有多个相似的 id。 我需要一个查询来处理这种情况,并在我加入它们时为每个 id 提供一行,如下所示:

     My_desired_table:
             id, name, val_TA, val_TB,val_TC_index1,val_TC_index2,Val_TC_index3
             01, bb  ,   ab  ,    ba,      cc      ,    cdf      ,     cba
             02, cc  ,   NULL,    bc,      NULL    ,    NULL     ,     NULL
             03, dd  ,   ac  ,  NULL,      ggg     ,    dfg      ,     NULL
             04, ff  ,   NULL,    bd,      NULL    ,    NULL     ,     NULL
             05, gg  ,   ad  ,  NULL,      NULL    ,    NULL     ,     NULL

【问题讨论】:

鉴于您正在尝试将行转置为列,您可能希望在加入之前查看 TableC 上的枢轴。 TableC 中的最大索引数是固定的还是动态的? 每个id的索引数是动态的。但是如果我们可以定义最大 20 的索引,我认为它是可行的。 【参考方案1】:

有几种方法可以实现这一点,但最简单的方法可能是 Dale K 在加入 tablec 之前向PIVOT 建议的那样。为了让您了解它是如何工作的,大致如下:

declare @main_table table (id varchar(5), name varchar(5));
declare @tablea table(id varchar(5), val varchar(5));
declare @tableb table(id varchar(5), val varchar(5));
declare @tablec table(id varchar(5), val varchar(5), idx int);

INSERT INTO @main_table
VALUES
('01','bb'),
('02','cc'),
('03','dd'),
('04','ff'),
('05','gg');

INSERT INTO @tablea
VALUES
('01','ab'),
('03','ac'),
('05','ad');

INSERT INTO @tableb
VALUES
('01','ba'),
('02','bc'),
('04','bd');

INSERT INTO @tablec
VALUES
('01','cc',1),
('01','cdf',2),
('01','cba',3),
('03','ggg',1),
('03','dfg',2);


with cte as (
    SELECT id, [1], [2], [3], [4]
    FROM
    @tablec c
    PIVOT
    (
        min(val)
        FOR idx
        IN ([1], [2], [3], [4])
    ) pvt
)
SELECT m.id, m.name, a.val AS val_TA, b.val AS val_TB, 
c.[1] AS val_TC_index1, c.[2] AS val_TC_index2, 
c.[3] AS val_TC_index3, c.[4] AS val_TC_index4
FROM @main_table m
LEFT JOIN @tablea a on a.id = m.id
LEFT JOIN @tableb b on b.id = m.id
LEFT JOIN cte c on c.id = m.id;

我给出了最多 4 个索引列,但是很容易看出如何扩展。如果您需要它是开放式的,那么您需要将其转换为动态 SQL。

请注意(因为您比较新),我已经为您完成了艰苦的工作(提供创建表和插入数据的语句)。以后在问此类问题时,请做类似的事情或使用db fiddle。你会得到更多的人愿意帮助你,如果他们不需要做这么多的打字。请记住,人们免费为您提供时间。

【讨论】:

【参考方案2】:

一种方法是聚合之前加入。但是,我会推荐一种使用横向连接的相关方法:

SELECT m.[id], m.[name], a.val, b.val, c.val1, c.val2, c.val3
FROM main_table m LEFT JOIN
     TableA a
     ON a.id = m.id LEFT JOIN
     TableB b
     ON b.id = m.id OUTER APPLY
     (SELECT MAX(CASE WHEN c.index = 1 THEN c.val END) as val1,
             MAX(CASE WHEN c.index = 2 THEN c.val END) as val2,
             MAX(CASE WHEN c.index = 3 THEN c.val END) as val3
      FROM TableC c
      WHERE c.id = m.id
     ) c;

【讨论】:

代码运行良好。肿瘤坏死因子。是的,当然。我明白了。【参考方案3】:

乔纳森的答案更可靠,但对于更简单的情况,您可以使用 GROUP BY 并聚合如下内容:

select
  A.id,
  max(A.val) as A_val,
  max(B.val) as B_val,
  count(*) as C_record_count,
  max(C.val) as C_max_val,
  min(C.val) as C_min_val
from TableA A
left join TableB B on A.id = B.id
left join TableC C on A.id = C.id
group by A.id

【讨论】:

以上是关于加入具有不同结构的多个表?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL - 从具有相同结构但数据不同的多个表中选择数据

加入多个字段,只过滤真正不同的行

从单个表中检索具有不同值的同一列的多个输出时的性能问题

Excel:通过多个工作表进行相关的下拉计算(具有不同的列位置)

与工会加入不同的记录

为来自不同表的两个单独操作运行多个子查询(相关)并加入一个表[关闭]