全外自我加入

时间:2013-06-22 16:11:23

标签: tsql

问题是返回包含空值的行。下面是创建表的SQL代码,并用示例数据填充它。

我期待以下,但查询不会显示具有空值的两行。

src_t1  id1_t1  id2_t1  val_t1     src_t2  id1_t2  id2_t2  val_t2

                                        b       z      z        4
a        w       w      100             b       w      w        1
a        x       x      200             b       x      x        2
a        y       y      300

数据:

CREATE TABLE sample (
    src VARCHAR(6)
    ,id1 VARCHAR(6)
    ,id2 VARCHAR(6)
    ,val FLOAT
);

INSERT INTO sample (src, id1, id2, val)
VALUES ('a', 'w', 'w', 100)
      ,('b', 'w', 'w', 1) 
      ,('a', 'x', 'x', 200)
      ,('b', 'x', 'x', 2) 
      ,('a', 'y', 'y', 300)
      ,('b', 'z', 'z', 4) 
;

这是我的测试查询。当t1.src ='a'和t1.id1 ='y'或t2.src ='b'和t2.id1 ='z'时,它不显示结果。

为什么呢?

什么是正确的查询?

SELECT t1.src, t1.id1, t1.id2, t1.val
  ,t2.src as src2, t2.id1, t2.id2, t2.val
FROM sample t1 FULL OUTER JOIN sample t2
  ON t1.id1 = t2.id1 AND t1.id2 = t2.id2
WHERE (t1.src = 'a' AND t2.src = 'b') 
  OR (t1.src IS NULL AND t1.id1 IS NULL AND t1.id2 IS NULL)
  OR (t2.src IS NULL AND t2.id1 IS NULL AND t2.id2 IS NULL)

我也尝试将WHERE子句中的条件移动到ON子句。

TIA。

2 个答案:

答案 0 :(得分:4)

WHERE子句计算得太晚,有效地将查询转换为内连接。

相反,使用正确的JOIN语法编写这样的查询:

SELECT t1.src, t1.id1, t1.id2, t1.val
  ,t2.src as src2, t2.id1, t2.id2, t2.val
FROM (
    select * from sample
    where src='a'
) t1 FULL OUTER JOIN (
    select * from sample 
    where src='b'
)  t2
  ON t1.id1 = t2.id1 AND t1.id2 = t2.id2

产生这个结果集:

src  id1  id2  val         src2 id1  id2  val
---- ---- ---- ----------- ---- ---- ---- -----------
a    w    w    100         b    w    w    1
a    x    x    200         b    x    x    2
NULL NULL NULL NULL        b    z    z    4
a    y    y    300         NULL NULL NULL NULL

<强>更新
还要注意使用两个子查询将源表清楚地分成两个不同的relvars。我第一次提交时错过了一分钟。

答案 1 :(得分:2)

实际上,我认为如果使用CTE,解决方案会更清晰一些:

WITH A AS (
  select * from sample where src='a'
),
B AS (
  select * from sample where src='b'
)
SELECT *
FROM A FULL OUTER JOIN B
    ON A.ID1 = B.ID1 AND A.ID2 = B.ID2
;