如何联接 SQL Server 中的多个列,并在一个表中包含其他表中不存在的列?

How do I join on multiple columns in SQL Server and include columns in one table that aren't present in other tables?

提问人:RMichalowski 提问时间:9/14/2019 最后编辑:jkdevRMichalowski 更新时间:9/17/2019 访问量:396

问:

我有两个表,其架构与示例表 1 和示例表 2 相似。两个表都有用于标识两个表中的数据的列。A 列和 B 列都在两个表中。

表1:

Col A   | Col B | Col C | Col D  
--------+-------+-------+------
Cat 1   | Bla a | C-1   | D-1  
Cat 1   | Bla a | C-2   | D-2  
Cat 1   | Bla a | C-3   | D-3  
Cat 2   | Bla b | C-4   | D-4   
Cat 2   | Bla b | C-5   | D-5  

表2:

Col A   | Col B | Col E  
--------+-------+------
Cat 1   | Bla a | E-1   
Cat 2   | Bla b | E-2   
Cat 2   | Bla b | E-3   
Cat 2   | Bla b | E-4

所需输出表:

Col A   | Col B | Col C | Col D | Col E  
--------+-------+-------+-------+------
Cat 1   | Bla a | C-1   | D-1   | E-1   
Cat 1   | Bla a | C-2   | D-2   | NULL  
Cat 1   | Bla a | C-3   | D-3   | NULL  
Cat 2   | Bla b | C-4   | D-4   | E-2    
Cat 2   | Bla b | C-5   | D-5   | E-3   
Cat 2   | Bla b | NULL  | NULL  | E-4

我需要合并、合并、更新、循环或以某种方式找到产生单个表的方法。在这个表中,我需要示例表 1 中唯一的列值与示例表 1 中的常见列值保持一致,就像它们在示例表 1 中所做的那样。我还需要示例表 2 中唯一的列中的值与示例表 2 中的常见列值保持一致。

如果一个表的公共列值匹配的记录多于另一个表,则唯一值应为 null,因为该记录将成为其他唯一值的占位符。

表 1 有 3 条记录,在 A 列和 B 列中具有值 Cat 1 和 Bla a。 表 2 有 1 条记录,在 A 列和 B 列中具有值为 Cat 1 和 Bla a。因此,所需的表必须具有两条记录,其 E 列的值为 null 或空白。

在尝试执行“联接”或“完全外联接”时,我得到了“示例错误输出”表中显示的结果。

所需输出表不应包含重复任一表中唯一值值的记录。这显示在示例错误输出表中。

错误输出示例:

Col A   | Col B | Col C | Col D | Col E  
--------+-------+-------+-------+------
Cat 1   | Bla a | C-1   | D-1   | E-1     
Cat 1   | Bla a | C-2   | D-2   | E-1    
Cat 1   | Bla a | C-3   | D-3   | E-1    
Cat 2   | Bla b | C-4   | D-4   | E-2  
Cat 2   | Bla b | C-4   | D-4   | E-3  
Cat 2   | Bla b | C-4   | D-4   | E-4  
Cat 2   | Bla b | C-5   | D-5   | E-2       
Cat 2   | Bla b | C-5   | D-5   | E-3  
Cat 2   | Bla b | C-5   | D-5   | E-4    
SQL 服务器

评论

1赞 Tim Leaf 9/14/2019
请使用您尝试的查询编辑您的答案。
1赞 Isaac 9/14/2019
通过在一行的 Col C 和 Col D(来自表 1)中为 NULL,在 Col E(来自表 2)中为其他行的 NULL 在我看来,您正在寻找一个完整的外部连接。但是,您的示例数据不支持这一点。
1赞 Isaac 9/14/2019
@TimLeaf我知道 FULL OUTER JOIN 不会使用此数据生成任何 NULL。我要说的是,如果存在一些不匹配,我认为能够产生 NULL 的唯一方法 FULL OUTER JOIN。
1赞 Isaac 9/14/2019
@RMichalowski您确定您的样本数据能够代表您的情况?如果是这样,我看不出有任何方法可以从您提供的数据中产生所需的结果。
1赞 George Stocker 9/17/2019
@RMichalowski 如果这是关于代码中的错误,我们需要看到你的查询用于生成“错误”答案。这个问题不是太宽泛,但我们遗漏了一些问题查询,这些查询会生成您遇到的错误输出。如果你能在问题标题中清楚地说明你的问题,也会有所帮助。

答:

-5赞 junketsu 9/14/2019 #1

我用测试脚本做了你的问题,预期的输出在块注释中,让我知道这是否是你要找的。

create table #t1 (
col_a varchar(5) null
,col_b varchar(5) null
,col_c varchar(5) null
,col_d varchar(5) null
)

create table #t2 (
col_a varchar(5) null
,col_b varchar(5) null
,col_e varchar(5) null
)


insert into #t1 values 
('Cat 1','Bla a','C-1','D-1')
,('Cat 1','Bla a','C-2','D-2')
,('Cat 1','Bla a','C-1','D-3')
,('Cat 2','Bla a','C-1','D-4')
,('Cat 2','Bla a','C-1','D-5')

insert into #t2 values 
('Cat 1'   , 'Bla a' , 'E-1'   )
,('Cat 2'   , 'Bla b' , 'E-2  ' )
,('Cat 2'   , 'Bla b' , 'E-3'   )
,('Cat 2'   , 'Bla b' , 'E-4')


select a.* , b.*
from #t1 a
inner join #t2 b on (a.col_a = b.col_a) and (b.col_b = a.col_b )
/* Expected output
col_a   col_b   col_c   col_d   col_a   col_b   col_e
Cat 1   Bla a   C-1 D-1 Cat 1   Bla a   E-1
Cat 1   Bla a   C-2 D-2 Cat 1   Bla a   E-1
Cat 1   Bla a   C-1 D-3 Cat 1   Bla a   E-1
*/

评论

2赞 Tim Leaf 9/14/2019
这甚至不是所要求的,您甚至没有在表中插入正确的值。
0赞 junketsu 9/14/2019
然后启发我@TimLeaf如果不是表 1,正确的表 1 应该是什么?显然它不是“所需的表”,也不是“错误的输出”
0赞 Isaac 9/14/2019
尽管值不正确,但@junketsu提供的查询是问题文本中要求的内容。
1赞 Isaac 9/14/2019
@junketsu #t1 的 Col B 和 Col C 的值不是 OP 指定的值。例如,#t1 中的所有行都有“Bla a”。OP 没有。
1赞 Tim Leaf 9/14/2019
但我仍然认为这无济于事,因为我想不出任何方法来使用提供的数据生成用户请求的数据集。我认为如果没有更多细节和/或用户的更正,我们无法提供帮助。
2赞 avery_larry 9/14/2019 #2
declare @t1 table (
col_a varchar(5) null
,col_b varchar(5) null
,col_c varchar(5) null
,col_d varchar(5) null
)

declare @t2 table (
col_a varchar(5) null
,col_b varchar(5) null
,col_e varchar(5) null
)


insert into @t1 values 
('Cat 1','Bla a','C-1','D-1')
,('Cat 1','Bla a','C-2','D-2')
,('Cat 1','Bla a','C-3','D-3')
,('Cat 2','Bla b','C-4','D-4')
,('Cat 2','Bla b','C-5','D-5')

insert into @t2 values 
('Cat 1'   , 'Bla a' , 'E-1'   )
,('Cat 2'   , 'Bla b' , 'E-2  ' )
,('Cat 2'   , 'Bla b' , 'E-3'   )
,('Cat 2'   , 'Bla b' , 'E-4')



select isnull(a.col_a,b.col_a) col_a, isnull(a.col_b,b.col_b) col_b, a.col_c,a.col_d,b.col_e
from (
    select *,row_number() over (partition by col_a order by col_c) rown
    from @t1
) a
full outer join (
    select *,row_number() over (partition by col_a order by col_e) rown
    from @t2
) b
    on a.col_a = b.col_a
    and a.col_b = b.col_b
    and a.rown = b.rown
order by isnull(a.col_a,b.col_a),isnull(a.rown,b.rown)

使用 row_number 作为完整联接的一部分是允许创建 null 值的原因。

评论

2赞 Isaac 9/14/2019
有“千里眼”徽章吗?如果是这样,@avery_larry应该得到这个答案。太棒了!
0赞 Tim Leaf 9/14/2019
哇,颜色给我留下了深刻的印象。我不太确定他们为什么想要这个输出,但这绝对提供了基于所提供数据的正确答案!干得好。
1赞 avery_larry 9/14/2019
在尝试将数据传递到单个矩阵的一个大表中的 SSRS 报告时,我做了类似的事情,但实际上应该是多个单独的表。行号上的完全联接可减少表中的空行数,并允许 SSRS 更快地处理数据。