Full Outer Join 自我与空值

Full Outer Join self with null values

我想进行包含空值的完整外部自联接。例如,如果 table 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 的值的解决方案不切实际。)

请看下面的代码:

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

输出是这样的:

两边都有null

也许是这样:

SELECT [Name]
       ,[1]
       ,[2]
FROM [table]
PIVOT
(
    MAX([val]) FOR [N] IN ([1], [2])
) PVT;

到目前为止,我只能将此视为一个联合。以及左右连接,因为你的标准发生了变化。

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让我们进一步扩展样本集:

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