【问题标题】:sql - multiple layers of correlated subqueriessql - 多层相关子查询
【发布时间】:2013-04-18 01:49:07
【问题描述】:

我有table A, B and C

我想返回表 A 中不存在于表 B 中且该列表中不存在于表 C 中的所有条目。

select * from table_A as a
where not exists (select 1 from table_B as b
where a.id = b.id)

这给了我 A 中不在 B 中的条目的第一个结果。但现在我只想要该结果中也不在 C 中的条目。

我尝试了以下口味:

select * from table_A as a
where not exists (select 1 from table_B as b
where a.id = b.id)
AND
where not exists (select 1 from table_C as c
where a.id = c.id)

但这不是正确的逻辑。如果有办法存储第一个查询的结果,然后从表 C 中不存在的结果中选择 *。但我不知道该怎么做。感谢您的帮助。

【问题讨论】:

  • 您使用的是什么数据库系统?

标签: sql sql-server correlated-subquery


【解决方案1】:

试试这个:

select * from (
  select a.*, b.id as b_id, c.id as c_id 
  from table_A as a
  left outer join table_B as b on a.id = b.id
  left outer join table_C as c on c.id = a.id
) T
where b_id is null
  and c_id is null

另一个实现是这样的:

select a1.*
from table_A as a1
inner join (
  select a.id from table_A
  except  
  select b.id from table_B
  except
  select c.id from table_c
) as a2 on a1.id = a2.id

注意here 中描述的对子查询形式的限制。第二种实现方式最简洁明了地向 SQL Server 描述了所需的操作,可能是最有效的。

【讨论】:

    【解决方案2】:

    您在第二个查询(的外部部分)中有两个 WHERE 子句。那不是有效的 SQL。如果您删除它,它应该会按预期工作:

    select * from table_A as a
    where not exists (select 1 from table_B as b
                      where a.id = b.id)
    AND
          not exists (select 1 from table_C as c            -- WHERE removed
                      where a.id = c.id) ;
    

    SQL-Fiddle 中测试(谢谢@Alexander)

    【讨论】:

      【解决方案3】:

      LEFT JOIN怎么样

      SELECT  a.*
      FROM    TableA a
              LEFT JOIN TableB b
                  ON a.ID = b.ID
              LEFT JOIN TableC c
                  ON a.ID = c.ID
      WHERE   b.ID IS NULL AND
              c.ID IS NULL
      

      【讨论】:

        【解决方案4】:

        NOT EXISTS 运算符的另一个选项

        SELECT *
        FROM dbo.test71 a 
        WHERE NOT EXISTS(
                         SELECT 1
                         FROM (SELECT b.ID
                               FROM dbo.test72 b
                               UNION ALL
                               SELECT c.ID
                               FROM dbo.test73 c) x
                         WHERE a.ID = x.ID
                         )  
        

        SQLFiddle上的演示

        来自@ypercube 的选项。感谢您的礼物;)

        SELECT *
        FROM dbo.test71 a 
        WHERE NOT EXISTS(
                         SELECT 1
                         FROM dbo.test72 b
                         WHERE a.ID = b.ID  
                         UNION ALL
                         SELECT 1
                         FROM dbo.test73 c
                         WHERE a.ID = c.ID
                         );
        

        SQLFiddle上的演示

        【讨论】:

        • 不错。您也可以在答案中添加此变体:SQL-Fiddle
        【解决方案5】:

        我不喜欢“不存在”,但如果出于某种原因它对你来说似乎更合乎逻辑;那么您可以为您的第一个查询使用别名。随后,您可以重新应用另一个“不存在”子句。比如:

        SELECT * FROM 
          ( select * from tableA as a
          where not exists (select 1 from tableB as b
          where a.id = b.id) )
        AS A_NOT_IN_B
        WHERE NOT EXISTS (
          SELECT 1 FROM tableC as c
          WHERE c.id = A_NOT_IN_B.id
        )
        

        【讨论】: