SQL - 在 WHERE 子句中使用 MAX 函数

10
假设 value 是一个整数,并且以下查询是有效的:

SELECT blah
FROM table
WHERE attribute = value

尽管 MAX(expression) 返回 int 类型,但以下语句是无效的:

SELECT blah
FROM table
WHERE attribute = MAX(expression)

当然可以使用子查询来实现所需的效果,但我的问题是为什么SQL被设计成这样-是否有某种原因导致不允许这种情况?那些从编程语言转过来的学生,他们总是可以通过函数调用替换数据类型来解决问题,会觉得这个问题很困惑。是否有一种解释可以给他们而不仅仅是说“就是这样”?


2
我能想到的最好解释是:max() 是一个聚合函数,这使它与标量函数不同(后者可用于where子句中)。由于聚合需要操作“行”,因此您无法将其应用于(标量)表达式。 - user330315
1
max(expression) 中,您正在考虑哪种表达式? - Conrad Frix
MAX() 来自哪个集合?该函数作用于一组数据,如果没有数据集,该函数会如何执行? - Hart CO
来自编程语言的学生可能会发现这个问题令人困惑。也许这是因为SQL是一种查询语言而不是编程语言。正则表达式和XSLT需要相同类型的思维模型转换,会引起类似的挫败感。 - Conrad Frix
5个回答

17

这只是一个查询操作顺序的问题。

  1. FROM 子句
  2. WHERE 子句
  3. GROUP BY 子句
  4. HAVING 子句
  5. SELECT 子句
  6. ORDER BY 子句

WHERE 只是过滤 FROM 返回的行。像 MAX() 这样的聚合函数无法返回结果,因为它甚至还没有应用于任何内容。

这也是为什么您不能在 WHERE 子句中使用在 SELECT 子句中定义的别名,但可以使用在 FROM 子句中定义的别名的原因。


在 HAVING 后面加上“窗口函数” :-) - dnoeth

6

一个where子句检查每一行,看它是否符合指定的条件。

max函数从一组行中计算出单个值。如果你把max或任何其他聚合函数放在where子句中,SQL服务器如何确定max函数可以使用哪些行,直到where子句完成过滤呢?

这涉及到SQL Server处理命令的顺序。它在GROUP BY或任何聚合之前运行WHERE子句。由于where子句先运行,SQL Server无法确定一行是否包含在聚合中,直到它处理完where子句。这就是HAVING子句的作用。HAVING在GROUP BY和WHERE之后运行,并且可以包括MAX,因为你已经过滤掉了不想使用的行。参见http://www.bennadel.com/blog/70-SQL-Query-Order-of-Operations.htm以获得有关SQL命令运行顺序的良好解释。


6
也许这可以工作。
SELECT blah
FROM table
WHERE attribute = (SELECT MAX(expresion) FROM table1)

2
WHERE子句专门设计用于针对原始数据(表中的单个行)测试条件。然而,MAX是一个聚合函数,可对多行数据执行操作。基本上,如果没有子查询,WHERE子句对于表中除当前行以外的任何行都一无所知。那么,当你甚至不知道这些行是什么时,如何确定整个数据集中的最大值呢?
是的,这有点简化了,特别是在处理联接时,但同样的原则适用。 WHERE总是逐行处理,因此它只知道当前行的情况。
即使你有一个GROUP BY子句,WHERE子句仍然只在分组之前处理原始数据中的一行。它不知道其他行中列的值,因此无法知道哪一行具有最大值。

1
假设这是MS SQL Server,以下内容可行。
SELECT TOP 1 blah
FROM table
ORDER BY expression DESC

“TOP” 仅在微软产品中实现。 - PM 77-1
尽管此答案复制了 OP 期望的结果,但它并不是问题的答案。而且在 OP 中没有指定他使用 MS 产品的地方,因此 TOP 只是一个“部分”解决方案。 - Barranka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接