为什么不能将OR或IN与OUTER JOIN操作一起使用?

时间:2018-08-03 13:00:09

标签: sql oracle

如果我在Oracle SQL数据库中使用以下查询(受此问题here的启发):

SELECT p.Name, a.Attribute
FROM People p
LEFT OUTER JOIN Attributes a
ON p.PersonID = a.PersonID 
WHERE a.Attribute IN ('Happy','Grouchy')
AND p.person_id IN ('Elmo', 'Oscar')

我会收到错误消息:

  

ORA-01719:OR或IN的操作数中不允许使用外部联接运算符(+)

这应该可以解决:

SELECT p.Name, a.Attribute
FROM People p
LEFT OUTER JOIN Attributes a
ON p.PersonID = a.PersonID AND a.Attribute IN ('Happy','Grouchy') AND p.person_id IN ('Elmo', 'Oscar')

谁能解释第一个版本调用错误的原因是什么?实际区别是什么?

4 个答案:

答案 0 :(得分:8)

顺便说一下,您已经在其中定义了一个内部联接。

通过在右手表中有一个子句,它必须满足两个条件。

SELECT p.Name, a.Attribute
FROM People p
LEFT OUTER JOIN Attributes a
ON p.PersonID = a.PersonID 
WHERE a.Attribute IN ('Happy','Grouchy') -- This means that the right side must exist also
AND p.person_id IN ('Elmo', 'Oscar') 

使用INNER JOIN或将此WHERE作为AND移至ON子句

答案 1 :(得分:2)

  

谁能解释第一个版本调用错误的原因是什么?

这只是Oracle决定这样做的方式:在使用OUTER JOIN时调用错误: https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4247209685061

  

实际区别是什么?

在这里,我也许可以为您提供更完整的解释(希望如此)...

与内部联接相比,

外部联接旨在允许您从表A中选择所有行(在示例表 people 中),并将来自表B的相应数据联接到同一结果行中(如果存在)。这意味着OUTER JOIN允许不存在表B数据。

enter image description here

将表B中的列放入WHERE子句时,您将使它们的存在成为强制性的(如果进行比较,它们必须存在),从而有效地使您的联接成为INNER JOIN。

enter image description here

另一方面,当您编写以下代码时:

LEFT OUTER JOIN Attributes a
ON p.PersonID = a.PersonID AND a.Attribute IN ('Happy','Grouchy') AND p.person_id IN ('Elmo', 'Oscar')

这等同于您编写了此内容:

LEFT OUTER JOIN (SELECT *
                   FROM Attributes
                  WHERE Attribute IN ('Happy','Grouchy')
                ) a   ON (p.PersonID = a.PersonID)
WHERE p.person_id IN ('Elmo', 'Oscar')

因此您已恢复使用OUTER JOIN。

答案 2 :(得分:1)

这只是Oracle实现(+)运算符的方式(很多年前):有些东西无法使用它。另一个例子是完全外部联接(只能在(+)运算符的帮助下,通过UNION ALL来制定)。

答案 3 :(得分:0)

您的查询是一个内部联接,因此您最好写:

SELECT p.Name, a.Attribute
FROM People p INNER JOIN
     Attributes a
     ON p.PersonID = a.PersonID 
WHERE a.Attribute IN ('Happy','Grouchy') AND
      p.person_id IN ('Elmo', 'Oscar');

由于LEFT JOIN中的WHERE值,NULL子句撤消了对a.Attribute的任何使用。

如果您想要一个没有匹配项的人,那么您确实希望LEFT JOIN 将第二张表上的条件移至ON子句:

SELECT p.Name, a.Attribute
FROM People p INNER JOIN
     Attributes a
     ON p.PersonID = a.PersonID AND
        a.Attribute IN ('Happy', 'Grouchy')
WHERE p.person_id IN ('Elmo', 'Oscar');