需要有关具有内部和外部联接的SQL查询的帮助

时间:2011-01-27 21:44:25

标签: sql syntax inner-join outer-join

我真的需要帮助才能正确获取此查询。我无法分享实际的表名和列名,但我会尽力布置问题。

假设以下表格。表格和密钥不能更改。期。我不在乎你是否认为这是一个糟糕的设计,这个问题不是一个设计问题,它是关于SQL语法的。

  • 表A - 名为id1的主键
  • 表B - 包含两个外键,TableA.id1和Foo.id2(忽略Foo,对此无关紧要)
  • 表C - 包含两个外键,TableA.id1和Foo.id2,另外有趣 列。

约束:

  1. SQL获取一组作为参数传入的id1。
  2. 必须返回表C行的列表。
  3. 它必须只返回表C行,其中表B行存在且匹配TableA.id1和Foo.id2 - 表C中的ARE行与表B不匹配
  4. 即使没有表C行,也必须为每个传入的id1返回一行。
  5. 首先,我尝试了从表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代替,但对于这种情况它似乎不是这样。它似乎有点罕见,这让其他开发者感到紧张,所以我很谨慎。

    所以,三个问题合而为一。

    1. 这是对的吗?
    2. 我是否正确使用了正确的外部连接?
    3. 是否有更清洁的方法来实现同样的目标?
    4. 编辑:DB是MySQL

3 个答案:

答案 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(或丢弃)中。

Q' S

  1. 是的,您的查询是正确的
  2. EXISTS应该更好用

答案 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子句来完成它,但这更清晰。