【问题标题】:SQL subqueries alternative to INTERSECTSQL 子查询替代 INTERSECT
【发布时间】:2012-01-23 16:26:21
【问题描述】:

我有两张桌子: PPC(主/从列 Id 加入)

Table P:
Id integer
Name varchar(12)

Table PC:
Id   integer
Code varchar(12)
Val  number

我想从 P 中获取满足以下同时条件的所有名称:

  • 拥有一台带有PC.Code='A'Val>100的PC

  • 拥有另一台带有PC.Code='B'Val>80 的PC

总之,我只对细节符合这两个条件的 P.Name 感兴趣。有没有不使用 INTERSECT 的方法来选择?

INTERSECT 查询是:

Select P.Name 
  from P, PC
 where P.Id=PC.Id
   and PC.Code='A' and Val>100
INTERSECT
Select P.Name 
  from P, PC
 where P.Id=PC.Id
   and PC.Code='B' and Val>80

(兴趣是检查性能并允许在 Access 中运行查询)

【问题讨论】:

  • This article 向您展示了如何使用 JOIN 重写 INTERSECT 查询。具体来说,请参阅 Vinko Vrsalovic 的解决方案。

标签: sql ms-access subquery intersect


【解决方案1】:

不知道性能怎么样..试试..

SELECT P.Name 
  FROM P
  INNER JOIN PC AS a ON P.Id=a.Id and a.Cod='A' and a.Val>100
  INNER JOIN PC AS b ON P.Id=b.Id and a.Cod='B' and a.Val>80

【讨论】:

    【解决方案2】:

    这是一种关系等效的替代方法(即消除重复行):

    SELECT P.Name 
      FROM P
     WHERE EXISTS (
                   SELECT * 
                     FROM PC
                    WHERE P.Id = PC.Id
                          AND PC.Code ='A' 
                          AND PC.Val > 100
                  )
          AND EXISTS (
                      SELECT * 
                        FROM PC
                       WHERE P.Id = PC.Id
                             AND PC.Code ='B' 
                             AND PC.Val > 80
                     );
    

    这里有几个语义等效的替代方案(因为它们可能返回重复的行):

    SELECT P.Name 
      FROM P, PC
     WHERE P.Id = PC.Id
           AND PC.Code ='A' 
           AND PC.Val > 100
           AND P.Name IN (
                          SELECT P1.Name 
                            FROM P AS P1, PC AS PC1
                           WHERE P1.Id = PC1.Id
                             AND PC1.Code = 'B' 
                                 AND PC1.Val > 80
                         );
    SELECT P.Name 
      FROM P, PC
     WHERE P.Id = PC.Id
           AND PC.Code ='A' 
           AND PC.Val > 100
           AND P.Name = ANY (
                             SELECT P1.Name 
                               FROM P AS P1, PC AS PC1
                              WHERE P1.Id = PC1.Id
                                AND PC1.Code = 'B' 
                                    AND PC1.Val > 80
                            );
    

    【讨论】:

      【解决方案3】:
      SELECT P.Name
        FROM P
        JOIN PC AS P1 ON P.Id = P1.Id AND P1.Cod = 'A' AND P1.Val > 100
        JOIN PC AS P2 ON P.Id = P2.Id AND P2.Cod = 'B' AND P2.Val >  80
      

      使用表别名 P1 和 P2 允许您进行 3 路连接。不过,它并不是完全自加入。这次不行。

      【讨论】:

        【解决方案4】:
        Select P.Name 
          from P, PC
         where P.Id=PC.Id
           and PC.Cod='A' and Val>100
           and exists (Select 1 From PC Where Id = P.Id and Cod = 'B' and Val > 80)
        

        【讨论】:

        • 您是否在 Access 中对此进行了测试?我问的原因是ValName是保留字。
        【解决方案5】:
        Select p.Name
        from P p
        inner join PC pc1 on p.Id = pc1.Id and pc1.Cod = 'A' and pc1.Val > 100
        inner join PC pc2 on p.Id = pc2.Id and pc2.Cod = 'B' and pc2.Val > 80
        

        【讨论】:

        • 不,这行不通,因为 PC.Cod 不能同时是“A”和“B”。您需要第二次加入。
        • 酷,我会投票赞成你取消投票反对的人...... :)
        • 您可以再次点击否决票,它会恢复正常:P 感谢您的警告!
        • 我会这样做,只是我一开始并没有对你投反对票!
        【解决方案6】:

        实际上不会使用这个,而是一个替代方案......

        SELECT P.Name
        FROM   P
               JOIN PC
                 ON P.Id = PC.Id
        WHERE  PC.Cod IN ( 'A', 'B' )
               AND Val > 80
        GROUP  BY P.Id,
                  P.Name
         HAVING MAX(CASE WHEN PC.Cod='A' and Val>100 THEN 1 END) = 1 
         AND MAX(CASE WHEN PC.Cod='B' and Val>80 THEN 1 END) = 1 
        

        或者对于 Microsoft Access,have 子句需要是

         HAVING MAX(IIf(PC.Cod='A' and Val>100, 1, 0)) = 1 
         AND MAX(IIf(PC.Cod='B' and Val>80, 1, 0)) = 1 
        

        【讨论】:

        • 不是通过否决票,而是令人难以置信的扭曲。它会起作用,但很难直接翻译需求。
        • @JonathanLeffler - OP 要求提供替代方案。这确实会通过表格。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-08-14
        • 1970-01-01
        • 2015-08-23
        • 1970-01-01
        • 2014-10-14
        • 1970-01-01
        • 2020-05-08
        相关资源
        最近更新 更多