高效使用SQL GROUP BY,SUM,COUNT

Dan*_*aca 4 sql performance group-by sum count

我有一张产品销售表,可能如下所示:

product   | amount   | ptype    | pdate      
p1        | 1.00     | sale     | 01/01
p1        | 2.00     | base     | 01/02
p2        | 1.50     | sale     | 02/03
p3        | 5.25     | base     | 10/10
Run Code Online (Sandbox Code Playgroud)

我想构建一个表格,每行显示一个产品,金额总和,如果产品是唯一的,则显示其他类型显示类型为"VAR",如果产品是唯一的则显示日期,否则显示日期为NULL.这样结果如下:

product   | total    | ptype    | pdate      
p1        | 3.00     | VAR      | (NULL)
p2        | 1.50     | sale     | 02/03
p3        | 5.25     | base     | 10/10
Run Code Online (Sandbox Code Playgroud)

我通过以下方式完成了我需要的结果:

SELECT DISTINCT product
,(SELECT SUM(amount) FROM T as b GROUP BY b.product HAVING a.product = b.product ) as total
,(SELECT CASE WHEN COUNT(*) = 1 THEN a.ptype  ELSE 'VAR' END from T as b GROUP BY b.product HAVING a.product = b.product) as ptype
,(SELECT CASE WHEN COUNT(*) = 1 THEN a.pdate  ELSE NULL END from T as b GROUP BY b.product HAVING a.product = b.product) as pdate
FROM T as a
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有更有效的方法来实现相同的结果.

dbe*_*ham 6

无需使用任何形式的子查询或内联视图.根据数据库引擎的复杂程度,这些结构可能会对性能产生负面影响.

这是您所要求的,即使是最原始的SQL引擎,它也应该可靠地对表进行单次扫描.

select product,
       sum(amount) as amount,
       case when count(*)=1 then min(ptype) else 'VAR' end as ptype,
       case when count(*)=1 then min(pdate) else null end as pdate
  from T
 group by product
Run Code Online (Sandbox Code Playgroud)

以下内容并不完全符合您的要求,但我认为它可能更贴近您实际需要的内容.如果组成聚合的多个不同值,它仅将ptype报告为VAR或pdate为NULL.

我添加了一个pcount列,这样你仍然可以识别单重聚合,即使ptype和pdate都不是nulll.

select product,
       sum(amount) as amount,
       count(*) as pcount,
       case when count(distinct ptype)=1 then min(ptype) else 'VAR' end as ptype,
       case when count(distinct pdate)=1 then min(pdate) else null end as pdate
  from T
 group by product
Run Code Online (Sandbox Code Playgroud)