使用左连接的查询不返回记录,尽管左表中的where子句应该找到单个记录。在这种情况下,它应该返回一个记录,其中左表中的字段包含值,右表中的字段为null,因为它们之间没有匹配。
显然,使用引用连接表达式上的右表的大小写存在问题。
在SQL Server中,相同的查询按预期工作。
select
t1.Description, t2.Description
from
A t1
left join
B t2
on
t1.Id = t2.Id and
1 = case when (
t2.Id = t2.Id and
(select t3.Flag from C t3 where t3.ID_B = t2.Id) = 'S'
) then 1 else 0
end
where t1.Id = 1
结果:没有返回任何行。
然后我移动了表达式t2.Id = t2.Id
(这里只是为了演示问题,并且应该总是返回true,显然)来自case表达式。
select
t1.Description, t2.Description
from
A t1
left join
B t2
on
t1.Id = t2.Id and
t2.Id = t2.Id and
1 = case when (
(select t3.Flag from C t3 where t3.ID_B = t2.Id) = 'S') then 1 else 0
end
where t1.Id = 1
结果:返回了一行。
上述查询仅用于演示问题,在实际情况下无用且未优化。
我想知道是否有人知道与此案相关的Oracle的任何限制。到目前为止,我们认为这是一个错误。
使用的数据:
答案 0 :(得分:1)
你认为t2.id = t2.id
总是正确的假设是错误的。如果值为NULL
,则将其视为false。我不认为这与这个特定的例子有关,只是为了澄清。
问题是如何处理left join
。这个想法很简单。处理on
子句。如果没有匹配项,则保留第一个表中的行。这与on
子句中的内容无关。 (这是一个功能描述;有许多可能的实现。)
根据您的示例数据,Oracle不正确。应返回一行。 SQL Server示例还应返回一行。我怀疑数据可能略有不同;我个人在SQL Server(或Oracle)中从未遇到过left join
的问题。
答案 1 :(得分:1)
CREATE TABLE t1 AS (SELECT 1 ID FROM dual);
CREATE TABLE t2 AS (SELECT 2 ID FROM dual);
CREATE TABLE t3 AS (SELECT 2 id_b, 's' flag FROM dual);
SELECT t1.*
FROM t1 LEFT JOIN t2
ON t1.ID = t2.ID
AND 1 = CASE WHEN t2.id = t2.id and (SELECT flag FROM t3 WHERE t3.id_b = t2.ID) = 's' THEN 1 ELSE 0 END
where t1.id = 1;
输出:no rows selected
结果看起来很奇怪,我想这可能是一个错误。
Oracle文档仅说明了 https://docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm#SQLRF52337
您无法在任何WHERE子句中将列与子查询进行比较 外部联接,无论您指定哪种形式。
通过查看上述查询的计划,我可以看到这种情况:
AND 1 = CASE WHEN t2.id = t2.id and (SELECT flag FROM t3 WHERE t3.id_b = t2.ID) = 's' THEN 1 ELSE 0 END
被解释为:
CASE WHEN (T2.ID(+)=T2.ID(+) AND (SELECT FLAG FROM T3 T3 WHERE T3.ID_B=:B1)='s') THEN 1 ELSE 0 END =1
并且在加入后计算。
我认为Oracle在执行连接之前无法计算CASE(因为T2.ID(+)=T2.ID(+)
)
答案 2 :(得分:1)
使用SQLFiddle Oracle 11g R2(感谢Shannon Severance)你的第一个查询给出记录计数:0但是只需删除CASE我们得到记录计数:1。(注意重命名t2Description。)
create table A (ID number(38), Description varchar(10));
create table B (ID number(38), Description varchar(10));
create table C (ID number(38), ID_B number(38), Flag varchar(10));
insert into A values(1, 'Item A1');
insert into B values(2, 'Item B1');
insert into C values(1, 2, 'S');
select
t1.Description, t2.Description as t2d
from
A t1
left join
B t2
on
t1.Id = t2.Id and
t2.Id = t2.Id and
(select t3.Flag from C t3 where t3.ID_B = t2.Id) = 'S'
where t1.Id = 1
这表明它与CASE错误估算有关。
请注意,在ON t2.Id中,至少有时(正确地)将其作为来自FROM产品的值,而不是在ON之后的NULL:
select
t1.Description, t2.Description as t2d
from
A t1
left join
B t2
on
-- for above data t2.id should be 1 here
t2.id is null
where t1.Id = 1
-- for above data t2.id should be null here
DESCRIPTION T2D
Item A1 (null)
我找到了这个链接:Outer Join Bug in Oracle 12c?