使用分组依据和汇总功能

时间:2019-04-17 07:11:14

标签: sql

我对SQL并不陌生,但是由于缺少一些知识,我觉得我从未完全理解SQL。我们都知道在使用分组依据时需要使用聚合函数,例如,我们有一个orderdetails表(带有orderid和productid的组合键),以编写查询以返回总价值(数量*单价)大于10,000的订单,SQL是:

select orderid, sum(qty*unitprice) AS totalvalue from Sales.OrderDetails
group by orderid
having sum(qty*unitprice) > 10000

我们知道选择是在分组和拥有之后发生的,所以当我来到

group by orderid
having sum(qty*unitprice) > 10000

如果我们可以将其成像为:

,我们已经按订单ID对所有记录进行了分组,并对所有费用进行了总和。

orderid  null(a column with no name but contains the total value)

123456   11000.00
987654   12184.00

然后是select子句:

select orderid, sum(qty*unitprice) AS totalvalue

因为我们已经在'having'子句之后得到了结果, 那么为什么我们需要再次执行“ sum(qty * unitprice)”来求和,不是那么多余吗?

让我烦恼的另一件事是:编写SQL时,select子句位于from子句之前,这非常不方便,因为您想获取列名的IntelliSense。当然,我可以先从caluse编写,然后再“插入” select子句,但是它使所有内容在逻辑上都是后退的。我是唯一对此有疑问的人吗? ... bizzare:(

2 个答案:

答案 0 :(得分:3)

它肯定是重复的,因此是不可取的,但是很难避免重复。您可以使用嵌套查询:

SELECT orderid, totalvalue
  FROM (SELECT orderid, SUM(qty * unitprice) AS totalvalue
          FROM sales.orderdetails
         GROUP BY orderid) AS order_value
 WHERE totalvalue > 10000

您需要查看DBMS的优化器计划,以确定这样做是否会对性能造成重大影响,但它避免了重复SUM(qty * price)表达式。理想情况下,优化器会将外部WHERE子句作为HAVING子句推送到内部查询中,但我不希望保证这样做(并且不同的系统可能会以不同的方式处理它)。

答案 1 :(得分:1)

首先,某些数据库允许HAVING中使用别名,因此您通常可以编写:

select orderid, sum(qty*unitprice) AS totalvalue
from Sales.OrderDetails
group by orderid
having totalvalue > 10000;

第二,SQL是一种说明性语言,而不是 procedural 语言。也就是说,执行的内容看起来与语句不一样。实际上,这是一个称为<有向图的无环图(在几乎所有数据库中),它没有SQL关键字可以识别的运算符。

这意味着即使两个相同的表达式在查询中多次出现,它们也可能只会被计算一次。或者在某些情况下,可能根本不评估表达式(例如select / exists子查询中的not exists表达式)。

第三,实际的sum()计算(在这种情况下)与查询完成的实际工作相比非常小。尤其是,性能问题是安排用于聚合的数据,而不是实际处理聚合功能。