【问题标题】:Efficient use of SQL GROUP BY, SUM, COUNT高效使用SQL GROUP BY、SUM、COUNT
【发布时间】:2012-06-30 15:21:32
【问题描述】:

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

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

我想建立一个表格,每行显示一个产品,金额的总和,如果产品是唯一的,则显示类型,否则将类型显示为“VAR”,如果产品是唯一的,则显示其他日期将日期显示为 NULL。使结果如下所示:

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

我正在通过执行以下操作来完成我需要的结果:

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

但我想知道是否有更有效的方法可以实现相同的结果。

【问题讨论】:

    标签: sql performance count group-by sum


    【解决方案1】:

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

    这是您所要求的,即使在最原始的 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
    

    以下内容并不完全符合您的要求,但我认为它可能更接近您实际寻找的内容。如果聚合中有多个不同的值,它只会将 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
    

    【讨论】:

      【解决方案2】:

      试试这段代码:

      SELECT DISTINCT product, x.total,
      IF(COUNT(x.ptype) > 1, 'VAR', x.ptype) AS ptype,
      IF(COUNT(x.pdate) > 1, NULL, x.pdate) AS pdate
      FROM (SELECT DISTINCT product, SUM(amount) AS total, ptype, pdate FROM table GROUP BY product) AS x
      JOIN table ON x.product = table.product
      GROUP BY x.product;
      

      希望它有效。

      【讨论】:

      • 此 SQL 不会在 SQL Server 上运行;不确定其他数据库引擎。
      • 在 Sybase 中,这给了我一个错误,提示“ptype”和“pdate”也必须出现在 GROUP BY 中。
      • 哇,我被那条裤子抓到了。完全忘记了要执行分组功能,您实际上需要对表格进行分组。
      【解决方案3】:

      如果您针对任何主要数据库(例如 SQL Server)运行此程序,查询优化器可能会代表您处理大部分优化。也就是说,您可以使用具有单个 group by 的内部查询轻松完成此操作。这是一个有效的示例,您可以使用:

      http://sqlfiddle.com/#!3/f2e05/19/1

      【讨论】:

      • 我的查询与@dbenham 提供的第一个查询几乎相同;我做了同样的观察,它可能不是你真正想要的。我会赞成这个答案。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 1970-01-01
      • 2012-11-20
      • 1970-01-01
      • 2011-04-18
      相关资源
      最近更新 更多