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

Query joining null values (left outer join)

继续 post 上的提问:

现在我有以下情况:

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

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

问题来自 2、3 或 4 等组合(TABLE_A 中的代码)。这些组合在 TABLE_Z 和 TABLE_X 中没有任何匹配值,所以最终结果应该是这样的:

我试图通过使用 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;

结果如下:

根据预期的结果,我应该能够得到如图所示的结果,但使用正确的组合显示。

查询失败的是什么?

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

我想一旦有了正确的查询,我就可以轻松地拆分它。像 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));

这给了我预期的结果:

现在的问题是上面说的屁股我需要通过将 TABLE_Z 、 TABLE_M 和 TABLE_Y 分成一个单独的视图来将它拆分成一个视图。 如果我直接拆分查询,我会发现我丢失了之前的结果......(我已经像下面那样拆分查询以便将 T1 作为我的新 VIEW 并且必须像我一样更改 JOINS 的顺序在没有 ON 子句的情况下保留 JOINS...)

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;

有什么方法可以将它拆分成一个单独的视图吗?

由于外连接条件中的 AND,您无法真正完成您正在尝试的事情。你部分地回到了 rBarryYoung 指出的空等价问题,但是如果你在你的外部连接中进行空检查,而不是在内联视图中(如果你的 [=40 的 none =] refs 为空),你得到了太多的记录。这得到 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 ,这就是你想要的。

但是它因为空值而崩溃了。在 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,就像你在 'correct' 中所做的那样查询。

我认为您可以拥有该视图的唯一方法是使用子查询分解(a.k.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 

...但这太可怕了,至少与你已经在做的事情相比是这样。