我该如何重写这些子查询

时间:2016-10-14 01:28:58

标签: sql postgresql subquery common-table-expression

在一个巨大的SQL查询上,如下所示:

SELECT
  ...
  (SELECT COUNT(*) FROM table1 WHERE field = 'bar' AND table1.table0_id = table0.id)
  (SELECT COUNT(*) FROM table1 WHERE field = 'foobar' AND table1.table0_id = table0.id)
  (SELECT COUNT(*) FROM table1 WHERE field = 'foo' AND table1.table0_id = table0.id)
  ...
FROM table0;

有没有办法避免在table0上为每次迭代运行3个查询?

由于

3 个答案:

答案 0 :(得分:3)

您可以使用条件聚合来简化查询

这是正确的方法

SELECT coalesce(b_count,0),
       coalesce(fb_count,0),
       coalesce(f_count,0)
FROM   table0 
       LEFT JOIN (SELECT table1.table0_id, 
                         Count(CASE WHEN field = 'bar' THEN 1 END) AS b_count, 
                         Count(CASE WHEN field = 'foobar' THEN 1 END) AS fb_count, 
                         Count(CASE WHEN field = 'foo' THEN 1 END) AS f_count, 
                  FROM   table1 
                  WHERE  field IN ( 'bar', 'foobar', 'foo' ) 
                  GROUP  BY table1.table0_id) table1 
              ON table1.table0_id = table0.id 

答案 1 :(得分:3)

Postgres 9.4 +

select
    count(table0.id) filter (where field = 'bar'),
    count(table0.id) filter (where field = 'foobar'),
    count(table0.id) filter (where field = 'foo')
from table1
left join table0 on table1.table0_id = table0.id
group by table0.id;

答案 2 :(得分:2)

我认为你不需要table0。您可以使用条件聚合:

SELECT table1.table0_id,
       SUM(CASE WHEN field = 'bar' THEN 1 ELSE 0 END) as bar,
       SUM(CASE WHEN field = 'foobar' THEN 1 ELSE 0 END) as foobar,
       SUM(CASE WHEN field = 'foo' THEN 1 ELSE 0 END) as foo
FROM table1
GROUP BY table1.table0_id;

如果table0中的值不在table1中,您可以使用left join

SELECT table2.id,
       SUM(CASE WHEN field = 'bar' THEN 1 ELSE 0 END) as bar,
       SUM(CASE WHEN field = 'foobar' THEN 1 ELSE 0 END) as foobar,
       SUM(CASE WHEN field = 'foo' THEN 1 ELSE 0 END) as foo
FROM table0 LEFT JOIN
     table1
     ON table0.id = table1.table0_id
GROUP BY table2.id;

您还可以将SELECT缩短为:

       SUM((field = 'bar')::int) as bar,
       SUM((field = 'foobar')::int) as foobar,
       SUM((field = 'foo')::int) as foo