如果我在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')
谁能解释第一个版本调用错误的原因是什么?实际区别是什么?
答案 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数据。
将表B中的列放入WHERE子句时,您将使它们的存在成为强制性的(如果进行比较,它们必须存在),从而有效地使您的联接成为INNER JOIN。
另一方面,当您编写以下代码时:
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');