【问题标题】:sql combine two subqueriessql合并两个子查询
【发布时间】:2010-06-11 21:08:26
【问题描述】:

我有两张桌子。表 A 有一个 id 列。表B 有一个Aid 列和一个type 列。示例数据:

A:  id
    --
    1
    2

B: Aid | type
   ----+-----
   1   |  1
   1   |  1
   1   |  3
   1   |  1
   1   |  4
   1   |  5
   1   |  4
   2   |  2
   2   |  4
   2   |  3

我想从表 A 中获取所有 ID,其中有一定数量的类型 1 和类型 3 操作。我的查询如下所示:

SELECT id 
FROM A
WHERE (SELECT COUNT(type)
       FROM B
       WHERE B.Aid = A.id
         AND B.type = 1) = 3 
  AND (SELECT COUNT(type)
       FROM B
       WHERE B.Aid = A.id
         AND B.type = 3) = 1

以上面的数据为例,应该只返回 id 1

我可以以某种方式组合这 2 个子查询吗?目标是使查询运行得更快。

【问题讨论】:

    标签: sql postgresql subquery


    【解决方案1】:

    postgres 是否支持 CTE?

    WITH counts (Counts, Type, Aid) as (
      select count(type), type
      from b group by Type, Aid
    )
      select id
      from A
      join Counts B1 on b1.Aid = a.id and b1.type = 1
      join Counts B3 on b3.Aid = a.id and b3.type = 3
    where
      b1.counts = 3 and b3.counts = 1
    

    我建议比较执行计划,但我怀疑它会相似,因为一切都应该在执行前折叠。

    【讨论】:

    【解决方案2】:
    Select ...
    From A
        Join    (
                Select B.Id
                    , Sum ( Case When B.Type = 1 Then 1 Else 0 End ) As Type1Count
                    , Sum ( Case When B.Type = 3 Then 1 Else 0 End ) As Type3Count
                From B
                Where B.Type In(1,3)
                Group By B.Id
                ) As Z
            On Z.Id = A.Id
    Where Z.Type1Count = 3
        And Z.Type3Count = 1
    

    【讨论】:

      【解决方案3】:

      这在 TSQL 中有效,在 Postgres 中有效吗?

      SELECT A.ID
      FROM A
      WHERE A.ID in
      (
      SELECT AID
      FROM B
      GROUP BY AID
      HAVING
        SUM(CASE WHEN Type = 1 THEN 1 ELSE 0 END) = 3
        OR SUM(CASE WHEN Type = 3 THEN 1 ELSE 0 END) = 1
      )
      

      【讨论】:

        【解决方案4】:

        另一种选择:

        SELECT DISTINCT Aid FROM (
           SELECT Aid,type,count(*) as n from B 
           GROUP BY Aid,type, ) as g 
         WHERE ( g.n=1 AND  g.type =  3 ) 
           OR  ( g.n=3 AND  g.type =  1 ) 
        

        不过,我怀疑这会比你原来的表现更好。 你似乎在做最好的策略:只计算候选行。 也许一些冗余的预过滤可能会有所帮助:

        SELECT DISTINCT Aid FROM (
           SELECT Aid,type,count(*) as n from B
           WHERE g.type =  3 OR g.type =  1  -- prefilter 
           GROUP BY Aid,type, ) as g 
         WHERE ( g.n=1 AND  g.type =  3 ) 
           OR  ( g.n=3 AND  g.type =  1 ) 
        

        【讨论】:

          猜你喜欢
          • 2016-05-26
          • 2020-12-23
          • 1970-01-01
          • 2017-05-18
          • 2016-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多