具有空值的完全外连接自身
Posted
技术标签:
【中文标题】具有空值的完全外连接自身【英文标题】:Full Outer Join self with null values 【发布时间】:2018-05-01 13:46:45 【问题描述】:我想做一个包含空值的完整外部自连接。例如,如果表 Data
看起来像:
N Name Val
--------------
1 ABC 8
1 DEF 7
2 ABC 9
2 XYZ 6
(其中N
是一个通用索引列,用于在顺序组上启用自联接),我这样做:
SELECT COALESCE(a.n, b.n) as n, COALESCE(a.Name, b.Name) as Name, a.Val as A, b.Val as B
FROM Data a
FULL OUTER JOIN Data b on a.N = b.N - 1 and a.Name = b.Name
我想要:
N Name A B
---------------
1 ABC 8 9
1 DEF 7 NULL
1 XYZ NULL 6
但我得到的更像是交叉连接:
n Name A B
--------------
1 ABC 8 9
1 DEF 7 NULL
2 ABC 9 NULL
2 XYZ 6 NULL
1 ABC NULL 8
1 DEF NULL 7
2 XYZ NULL 6
如何执行此完全外部联接以获得精简的自联接结果?
(注意:实际上列N
是一个通用索引,因此需要命名N
的值的解决方案并不实用。)
【问题讨论】:
【参考方案1】:到目前为止,我只能将其视为工会。以及左右连接,因为您所追求的标准发生了变化。
SELECT COALESCE(a.Name, b.Name) as Name, a.Val as A, b.Val as B
FROM Data a
LEFT JOIN Data b on a.Name = b.Name
and B.N = 2
WHERE A.N = 1
UNION
SELECT COALESCE(a.Name, b.Name) as Name, a.Val as A, b.Val as B
FROM Data a
RIGHT JOIN Data b on a.Name = b.Name
and A.N = 1
WHERE B.N = 2
给我们:
+------+---+----+
| NAME | A | B |
+------+---+----+
| ABC | 8 | 9 |
| DEF | 7 | |
| XYZ | | 6 |
+------+---+----+
然而,这依赖于一个硬编码的 N 值,我认为这不是很有用...工作得更好。
【讨论】:
是的,这就是诀窍:N
是一个允许顺序自连接的索引列,所以我不能使用N
的命名值....
刚刚更新了问题以明确N
是输出的一部分。【参考方案2】:
由于我们要处理广义自连接索引列N
,让我们进一步扩展样本集:
create table #Data (n int, name char(3), val int)
insert into #Data values (1, 'ABC',8)
insert into #Data values (1, 'DEF',7)
insert into #Data values (2, 'ABC',9)
insert into #Data values (2, 'XYZ',6)
insert into #Data values (3, 'ABC',9)
insert into #Data values (3, 'DEF',5)
insert into #Data values (3, 'XYZ',4)
对于这个示例,我们希望 SQL 产生这个输出:
N Name A B
---------------
1 ABC 8 9
1 DEF 7 NULL
1 XYZ NULL 6
2 ABC 9 9
2 DEF NULL 5
2 XYZ 6 4
以下代码适用于一般情况:
SELECT COALESCE(a.n, b.n-1) as i, COALESCE(a.Name, b.Name) as Name, a.Val as A, b.Val as B
FROM #Data a
FULL OUTER JOIN #Data b ON a.N = b.N - 1 AND a.Name = b.Name
WHERE a.n < (SELECT MAX(n) FROM #Data) -- Deals with end index case
OR (a.n is null AND b.n-1 IN (SELECT DISTINCT n FROM #Data))
ORDER BY COALESCE(a.n, b.n-1), Name
要了解为什么会这样,一个很好的中间步骤是注意当a.N = 1
我们想要n = 1
来自的行:
SELECT COALESCE(a.n, b.n - 1) as n, COALESCE(a.Name, b.Name) as Name,
a.Val as A, b.Val as B
FROM #Data a
FULL OUTER JOIN #Data b ON a.N = b.N - 1 AND a.Name = b.Name
【讨论】:
【参考方案3】:请看下面的代码:
create table Data (n int, name char(3), val int)
insert into data values (1, 'ABC',8)
insert into data values (1, 'DEF', 7)
insert into data values (2 , 'ABC' , 9)
insert into data values (2 , 'XYZ', 6)
SELECT COALESCE(a.Name, b.Name) as Name, a.Val as A, b.Val as B
FROM Data a
FULL OUTER JOIN Data b on a.N = b.N - 1 and a.Name = b.Name
输出是这样的:
两边都有空值。
【讨论】:
哎呀...是的,你是对的;我以一种没有显示这一点的方式限制我的测试数据。我正在修复原始问题以反映这一点。 (请注意,它仍然没有按照我想要的方式加入。)【参考方案4】:也许是这样的:
SELECT [Name]
,[1]
,[2]
FROM [table]
PIVOT
(
MAX([val]) FOR [N] IN ([1], [2])
) PVT;
【讨论】:
聪明。但是N
列是一个大索引,所以我需要一个可概括的情况,我不必命名N
的每个可能值。以上是关于具有空值的完全外连接自身的主要内容,如果未能解决你的问题,请参考以下文章