我对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:(
答案 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()
计算(在这种情况下)与查询完成的实际工作相比非常小。尤其是,性能问题是安排用于聚合的数据,而不是实际处理聚合功能。