查询连接空值(左外连接)

时间:2015-03-06 15:04:48

标签: sql oracle join outer-join

继续对帖子提出的要求:

Ora SQL Query: joining without references

现在我有以下情况:

我们的想法是通过TABLE_A中的输入从TABLE_M中获取组合。

例如。 TABLE_A中的记录1(CODE = 1)对应于COMBINATION1,同时分别通过TABLE_Z和TABLE_X ...

问题来自于2,3或4之类的组合(TABLE_A中的CODE)。这些组合在TABLE_Z和TABLE_X中没有任何匹配值,因此最终结果应该是这样的:

  • TABLE_A(code2)----> COMBINATION 7
  • TABLE_A(code3)---->组合9
  • TABLE_A(code4)---->组合8

我试图通过使用OUTER JOINS来实现这一目标,但却无法成功实现...... :(

SELECT A.REF_X,A.REF_Z, X.CODE,Z.CODE,M.DESCR 
    FROM TABLE_A A
    LEFT OUTER JOIN TABLE_Z Z
      ON A.REF_Z = Z.CODE
    LEFT OUTER JOIN TABLE_X X
      ON A.REF_X = X.CODE
    LEFT OUTER JOIN TABLE_M M
      ON Z.REF1 = M.Z_REF1
      AND Z.REF2 = M.Z_REF2
      AND Z.REF3 = M.Z_REF3
      AND X.REF1=M.X_REF1;

结果如下:

enter image description here

根据预期的结果,我应该能够获得如图所示的东西,但是使用了正确的COMBINATION showm。

查询失败的是什么?

之后,我们的想法也是将它放在两个独立的视图中。

我想,一旦我有了正确的查询,我就可以轻松地将其拆分。类似CORE_VIEW的东西,包含TABLE_Z,TABLE_X和TABLE_M,另一个视图将连接TABLE_A和CORE_VIEW。

然后,代码可重用性会很容易。


在Barry的评论之后,我能够生成正确的查询:

SELECT A.REF_X,A.REF_Z, X.CODE,Z.CODE,M.DESCR 
FROM TABLE_A A
LEFT OUTER JOIN TABLE_Z Z
  ON  A.REF_Z = Z.CODE
LEFT OUTER JOIN TABLE_X X
  ON  A.REF_X = X.CODE
LEFT OUTER JOIN TABLE_M M
  ON  (Z.REF1 = M.Z_REF1 OR (Z.REF1 IS NULL AND M.Z_REF1 IS NULL))
  AND (Z.REF2 = M.Z_REF2 OR (Z.REF2 IS NULL AND M.Z_REF2 IS NULL))
  AND (Z.REF3 = M.Z_REF3 OR (Z.REF3 IS NULL AND M.Z_REF3 IS NULL))
  AND (X.REF1 = M.X_REF1 OR (X.REF1 IS NULL AND M.X_REF1 IS NULL));

这给了我预期的结果:

enter image description here

现在的问题是上面说的我需要将TABLE_Z,TABLE_M和TABLE_Y分成一个sepparate视图,将它拆分成一个视图。 如果我直接拆分查询,我看到我放弃了之前的结果...(我已经拆分了下面的查询,以便将T1作为我的新视图,并且必须改变JOINS的顺序,因为我是离开JOINS没有ON子句......)

SELECT A.REF_X,A.REF_Z, T1.X_CODE, T1.Z_CODE, T1.DESCR
FROM TABLE_A A
LEFT OUTER JOIN 
    (SELECT X.CODE X_CODE,Z.CODE Z_CODE,M.DESCR  
    FROM TABLE_Z Z
    LEFT OUTER JOIN TABLE_M M
      ON  (Z.REF1 = M.Z_REF1 OR (Z.REF1 IS NULL AND M.Z_REF1 IS NULL))
      AND (Z.REF2 = M.Z_REF2 OR (Z.REF2 IS NULL AND M.Z_REF2 IS NULL))
      AND (Z.REF3 = M.Z_REF3 OR (Z.REF3 IS NULL AND M.Z_REF3 IS NULL))
    LEFT OUTER JOIN TABLE_X X  
      ON (X.REF1 = M.X_REF1 OR (X.REF1 IS NULL AND M.X_REF1 IS NULL))
    ) T1
ON   A.REF_X = T1.X_CODE
AND  A.REF_Z = T1.Z_CODE;

enter image description here

有什么方法可以将它拆分成一个sepparate View吗?

1 个答案:

答案 0 :(得分:2)

由于外部连接条件中的AND,您无法真正完成所尝试的操作。你部分回到了rBarryYoung所指出的null等价问题,但如果你这样做,则检查你的外连接,而不是内联视图(如果没有,你的TABLE_X / Z refs都不为null) ,你得到的记录太多了。这会得到16行,你想要的那些加上一些垃圾:

SELECT A.REF_X, A.REF_Z, T1.X_CODE, T1.Z_CODE, T1.DESCR
FROM TABLE_A A
LEFT JOIN (
  SELECT X.CODE X_CODE,Z.CODE Z_CODE,M.DESCR
  FROM TABLE_M M
  LEFT JOIN TABLE_Z Z
  ON Z.REF1 = M.Z_REF1
  AND Z.REF2 = M.Z_REF2
  AND Z.REF3 = M.Z_REF3
  LEFT JOIN TABLE_X X
  ON X.REF1 = M.X_REF1
) T1
ON (T1.X_CODE = A.REF_X OR (T1.X_CODE IS NULL))
AND (T1.Z_CODE = A.REF_Z OR (T1.Z_CODE IS NULL));

如果您只是尝试拆分X_REF值:

SELECT M.CODE M_CODE, X.CODE X_CODE, M.DESCR
FROM TABLE_M M
LEFT JOIN TABLE_X X
ON X.REF1 = M.X_REF1

...你会得到30排;对于X_CODE A,您有四种可能的组合,1,3,5或7.对于Z_REF,它类似:

SELECT M.CODE M_CODE, Z.CODE Z_CODE, M.DESCR
FROM TABLE_M M
LEFT JOIN TABLE_Z Z
ON Z.REF1 = M.Z_REF1
AND Z.REF2 = M.Z_REF2
AND Z.REF3 = M.Z_REF3

......获得18行;对于Z_CODE Z,你有三种可能的组合,1,2和8.现在,你可以比较这两个列表,看看对于A和Z的TABLE_A组合,唯一重叠的组合是数字1,这就是你想要的。 / p>

但是因为空值而崩溃了。在X_CODE列表中,对于组合8和9,您将获得两个空匹配。在Z_CODE列表中,您将获得两个空匹配,分别为7和9.一旦添加OR (T1.X_CODE IS NULL)OR (T1.Z_CODE IS NULL),您将获得这些匹配同样,对于TABLE_A A和Z,你得到组合1(其中A和Z匹配),7(A匹配),8(Z匹配)和9(不匹配)。

如果您没有OR ... IS NULL条件,那么当两个TABLE_A列匹配时,您会得到正确的答案,但是当任何一列不匹配时您没有得到任何结果,正如您在结果中看到的那样你包括在这个问题中。中间没有任何东西。

所以你必须从TABLE_A驱动它并通过TABLE_X和TABLE_Z加入TABLE_M,正如你在'正确'的查询中所做的那样。

我能看到你的唯一方法就是使用子查询因子分析(a.k.a a CTE)或实际视图,以及带有四个分支的联合来处理可能的场景:

WITH T1 AS (
  SELECT X.CODE X_CODE,Z.CODE Z_CODE,M.DESCR
  FROM TABLE_M M
  LEFT JOIN TABLE_Z Z
  ON Z.REF1 = M.Z_REF1
  AND Z.REF2 = M.Z_REF2
  AND Z.REF3 = M.Z_REF3
  LEFT JOIN TABLE_X X
  ON X.REF1 = M.X_REF1
)
SELECT A.REF_X, A.REF_Z, T1.X_CODE, T1.Z_CODE, T1.DESCR
FROM TABLE_A A
JOIN T1 ON T1.X_CODE = A.REF_X AND T1.Z_CODE = A.REF_Z
UNION ALL
SELECT A.REF_X, A.REF_Z, T1.X_CODE, T1.Z_CODE, T1.DESCR
FROM TABLE_A A
JOIN T1 ON T1.X_CODE = A.REF_X AND T1.Z_CODE IS NULL
WHERE NOT EXISTS (SELECT 1 FROM T1 WHERE Z_CODE = A.REF_Z)
UNION ALL
SELECT A.REF_X, A.REF_Z, T1.X_CODE, T1.Z_CODE, T1.DESCR
FROM TABLE_A A
JOIN T1 ON T1.Z_CODE = A.REF_Z AND T1.X_CODE IS NULL
WHERE NOT EXISTS (SELECT 1 FROM T1 WHERE X_CODE = A.REF_X)
UNION ALL
SELECT A.REF_X, A.REF_Z, T1.X_CODE, T1.Z_CODE, T1.DESCR
FROM TABLE_A A
JOIN T1 ON T1.Z_CODE IS NULL AND T1.X_CODE IS NULL
WHERE NOT EXISTS (SELECT 1 FROM T1 WHERE X_CODE = A.REF_X OR Z_CODE = A.REF_Z);

确实得到:

REF_X REF_Z X_CODE Z_CODE DESCR       
----- ----- ------ ------ ------------
A     Z     A      Z      COMBINATION1 
C     Y     C      Y      COMBINATION4 
D     U     D      U      COMBINATION3 
F     W     F      W      COMBINATION6 
A     FFF   A             COMBINATION7 
TTT   T            T      COMBINATION8 
SSS   JJJ                 COMBINATION9 

......但这非常可怕,至少与你已经工作过的相比。