加入具有不同结构的多个表?
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
【讨论】:
以上是关于加入具有不同结构的多个表?的主要内容,如果未能解决你的问题,请参考以下文章