我真的需要帮助才能正确获取此查询。我无法分享实际的表名和列名,但我会尽力布置问题。
假设以下表格。表格和密钥不能更改。期。我不在乎你是否认为这是一个糟糕的设计,这个问题不是一个设计问题,它是关于SQL语法的。
约束:
首先,我尝试了从表A到表B的左外连接,然后是内连接到表C.这违反了上面的第4条规则,因为内连接会丢弃这些行。
接下来我尝试了两个Left Outer连接。这更接近,但是具有包括与表A连接到表B的行的副作用,但是没有相应的表C条目,这不是我想要的。
所以,这就是我想出来的。
SELECT
a.id1,
c.*
FROM
TableB b
INNER JOIN
TableC c USING (id1,id2)
RIGHT OUTER JOIN
TableA a USING (id1)
WHERE
a.id1 in (x,y,z)
我对Right Outer Join有点警惕,因为我读过的文档说它可以用Left Outer代替,但对于这种情况它似乎不是这样。它似乎有点罕见,这让其他开发者感到紧张,所以我很谨慎。
所以,三个问题合而为一。
编辑:DB是MySQL
答案 0 :(得分:2)
您可以使用括号将其重写为LEFT OUTER JOIN。在伪SQL中改变了这个:
SELECT ...
FROM b
INNER JOIN c ON ...
RIGHT OUTER JOIN a ON ...
到此:
SELECT ...
FROM a
LEFT OUTER JOIN (
b INNER JOIN c ON ...
) ON ...
答案 1 :(得分:1)
您可以使用EXISTS子句,有时效果更好
SELECT
a.id1,
c.*
FROM TableA a
LEFT JOIN TableC c
ON c.id1 = a.id1 AND EXISTS (
select *
from TableB b
where b.id1=c.id1 and b.id2=c.id2)
WHERE
a.id1 in (x,y,z)
正如您所写,它的工作原理是因为ANSI JOIN始终处理从上到下。由于您需要在加入A之前针对C测试B,因此它是在不引入子查询[(B x C) RIGHT JOIN A]
的情况下编写它的唯一方法。 但是,错误的查询计划可以在正确加入A之前执行B和C (B x C)
中的所有记录。
EXISTS 方法有效地使用A上的过滤器,然后LEFT JOINs到C和每个找到的C,验证它也存在于B(或丢弃)中。
答案 2 :(得分:0)
是的,您需要从TableA开始,然后使用连接添加表B和C.您甚至需要TableA的唯一原因是确保每个参数都有一行。
Select a.id1,c.*
From
TableA a
Left Join TableB b on a.id1=b.id1
Left Join TableC c on b.id1=c.id1 and b.id2=c.id2
Where a.id1 in (x,y,z)
您需要一直进行OUTER连接,或者B中缺少的行也会导致A中的数据从结果集中过滤掉。通过将C连接到B(而不是直接连接到A),您使用B进行过滤。您可以使用复杂的EXISTS子句来完成它,但这更清晰。