【问题标题】:Why are aggregate functions not allowed in where clause为什么 where 子句中不允许使用聚合函数
【发布时间】:2017-07-17 04:28:58
【问题描述】:

我正在寻求对此的澄清。我在下面写了两个查询:

我们有一个员工姓名表,其中包含 ID、姓名、工资等列

  1.  Select name from employee 
    where sum(salary) > 1000 ;

  2.  Select name from employee 
    where substring_index(name,' ',1) = 'nishant' ;

查询 1 无效,但查询 2 有效。根据我的开发经验,我觉得可能的解释是:

sum() 作用于参数中指定的一组值。这里 'salary' 列已通过,因此它必须将所有值相加 柱子。但是在 where 子句中,记录会被一一检查, 就像第一条记录 1 被检查以进行测试,依此类推。因此 sum(salary) 不会被计算,因为它需要访问所有列 值,然后只有它会返回一个值。

查询 2 作为 substring_index() 作用于单个值,因此在这里它作用于提供给它的值。

您能否验证我的理解。

【问题讨论】:

  • 您认为查询 1 可以实现什么目标?你认为它做什么/应该做什么(用英语)?所以你想要每个“工资总和”高于 1000 的员工的姓名?但是每个员工只有一份工资,那么“工资总和”是什么意思呢?
  • @ErwinBolwidt 如果代替 sum(),我使用的是 avg(),假设我想要薪水高于 avg() 的员工。我只想验证我为什么不能在 where 子句中使用聚合函数的解释。
  • @user3527008 - 您可以在having 子句中使用它们
  • @AlexPoole - 我读到这个问题的意思是,“为什么 SQL 的设计者需要限制聚合函数的使用,所以它们只能在 HAVING 子句中而不是 @987654324 @?他们不能出现在WHERE子句中是否有合理的原因?"
  • 当然,一个更好的问题是“为什么不能有一个像 where sal = max(sal)where sal > avg(sal) 这样的 where 子句(即使没有 group by 子句 - 将所有行放在一个组)。正如我解释的那样,原因是这需要循环推理,因为 maxavg 并未应用于基表中的所有行;它们仅应用于满足 @987654332 的行@ 条件!如果整个基表需要maxavg,则必须在子查询中单独计算。

标签: sql oracle aggregate-functions


【解决方案1】:

不能在WHERE 子句中使用SUM() 的原因是子句的求值顺序。

FROM 告诉你从哪里读取行。在将行从磁盘读取到内存时,会检查它们是否符合WHERE 条件。 (实际上在许多情况下,WHERE 子句失败的行甚至不会从磁盘读取。“条件”正式称为 谓词,并且查询执行引擎使用一些谓词来决定从基表中读取哪些行。这些称为 access 谓词。)如您所见,WHERE 子句在呈现给引擎时应用于每一行。

另一方面,只有在读取了所有行(验证所有谓词)之后才进行聚合。

想一想:SUM() 仅适用于满足WHERE 条件的行。如果您将SUM() 放在WHERE 子句中,则您要求的是循环逻辑。新行是否通过WHERE 子句?我怎么会知道?如果会通过,那么我必须将其包含在SUM 中,但如果没有,则不应将其包含在SUM 中。那么我该如何评估SUM 条件呢?

【讨论】:

  • 先生的解释太棒了。哇
  • 如果您正在寻找解决方案,您可能需要做的就是将您的 WHERE 语句移动到 HAVING 子句中。
  • @deed02392 - 如果你在事实发生三年半后跳进去,也许你应该阅读这个问题,直到你首先理解它。 OP 想了解条件 必须HAVING 子句中而不是在 WHERE 子句中的理论原因。解决方案(与您提出的相同)很容易给出并为所有人所知。更微妙的问题是为什么只能这样做。您可能还想阅读 OP 问题下的 cmets,其中进一步澄清了此线程的目的。
【解决方案2】:

为什么不能在where子句中使用聚合函数

聚合函数适用于数据集。 WHERE 子句不能访问整个集合,只能访问它当前正在处理的行。

你当然可以使用 HAVING 子句:

select name from employee 
group by name having sum(salary) > 1000;

如果必须使用WHERE,可以使用子查询:

select name from (
    select name, sum(salary) total_salary from employee
    group by name
) t where total_salary > 1000;

【讨论】:

  • 正是我想要的!!!只是标题需要编辑:D。但再次感谢:)
【解决方案3】:

sum() 是一个聚合函数。通常,您希望它可以与group by 一起使用。因此,您的第一个查询缺少group by。在group by 查询中,having 用于在聚合之后进行过滤

Select name
from employee 
group by name
having sum(salary) > 1000 ;

【讨论】:

  • 我只是想验证我为什么不能在 where 子句中使用聚合函数的解释。
【解决方案4】:

使用有工作,因为查询直接到该列中的行,而 where 失败,因为只要不满足条件,查询就会不断来回循环。

【讨论】:

    猜你喜欢
    • 2017-06-16
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-26
    相关资源
    最近更新 更多