查询连接空值(左外连接)
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 中没有任何匹配值,所以最终结果应该是这样的:
- TABLE_A (code2) ----> 组合 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;
结果如下:
根据预期的结果,我应该能够得到如图所示的结果,但使用正确的组合显示。
查询失败的是什么?
之后的想法也是将它放在两个独立的视图中。
我想一旦有了正确的查询,我就可以轻松地拆分它。像 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
...但这太可怕了,至少与你已经在做的事情相比是这样。
继续 post 上的提问:
现在我有以下情况:
想法是通过 TABLE_A 中的输入从 TABLE_M 中获得组合。
例如。 TABLE_A中的记录1(CODE=1)对应COMBINATION1,分别经过TABLE_Z和TABLE_X...
问题来自 2、3 或 4 等组合(TABLE_A 中的代码)。这些组合在 TABLE_Z 和 TABLE_X 中没有任何匹配值,所以最终结果应该是这样的:
- TABLE_A (code2) ----> 组合 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;
结果如下:
根据预期的结果,我应该能够得到如图所示的结果,但使用正确的组合显示。
查询失败的是什么?
之后的想法也是将它放在两个独立的视图中。
我想一旦有了正确的查询,我就可以轻松地拆分它。像 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
...但这太可怕了,至少与你已经在做的事情相比是这样。