在这种情况下,为什么我需要创建一个子查询而不是仅仅进行比较?
Why do I need to create a subquery instead of just comparing in this case?
我写了这个查询
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM employees
WHERE SALARY > (SELECT AVG(SALARY)
FROM employees)
我有点困惑为什么我必须为它创建一个子查询,为什么我不能像这样写查询:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM employees
WHERE SALARY > AVG(SALARY)
SQL 是一种基于集合的语言。如果您只聚合一组中的一列,则必须聚合整个集合。您不能既聚合一个集合又不聚合一个集合。此外,SELECT
语句仅定义一个集合。因此,您无法在同一 SELECT 语句中将聚合集中的值与 non-aggregated 集(两组)中的值进行比较。
您的第一个语句有效,因为您有两个 SELECT 语句,每个语句都定义了一个不同的集合。一组通过 avg()
函数聚合,另一组保持 non-aggregated.
它也有效,因为聚合集是标量的(它只有一个值)。它可以将 non-aggregated 集中的每一行与 single-value 聚合集中保存的标量值进行比较。如果以非标量的方式定义聚合集,则会抛出错误,您将不得不通过 [=17] 中的 ON
子句在两个集合之间建立关系=] 在您的 FROM
子句中或通过相关的子查询。
另一个原因是操作顺序。通过 WHERE
子句的过滤首先发生在 SQL 的执行中。在过滤您的数据时,尚未发生其他操作。 GROUP BY/Aggregation 在 SQL 的执行中出现得很晚。因此,您试图将 SQL 中两个截然不同的步骤的结果相互比较。
操作顺序是HAVING
存在的原因。它与 WHERE
非常相似,但在聚合之后起作用。不过,这对您在此 SQL 中尝试做的事情没有帮助,因为您再次尝试将 non-aggregated 集合中的值与聚合集合中的值进行比较不能在单个 SELECT 语句中完成。
可能值得注意的是,您可以使用“window 函数”(也称为“有序分析函数”或“分析函数”)在 non-aggregated 集合内聚合 (so-to-speak) ") 大多数 RDBMS 都支持。
例如:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY, AVG(SALARY) OVER () as avg_salary
FROM employees;
这仍然会为 table employees
中的每一行吐出一个 non-aggregated 行。它将有第 4 列,其中每一行包含所有员工的平均工资。 每一行都包含相同的值。
+-------------+------------+------------+--------+------------+
| EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | avg_salary |
+-------------+------------+------------+--------+------------+
| 1 | bob | mcbob | 100 | 210 |
| 2 | sue | o'susan | 230 | 210 |
| 3 | venkat | van venkat | 300 | 210 |
+-------------+------------+------------+--------+------------+
也就是说,由于操作顺序的原因,您不能比较 WHERE
或 HAVING
子句中 window 函数的结果。 Window 函数逻辑几乎在 sql 执行的每一步之后运行。您只会得到一个不允许的错误。因此,您将再次需要两个 SELECT 语句:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM
(
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY, AVG(SALARY) OVER () as avg_salary
FROM employees;
) dt
WHERE SALARY > avg_salary;
最后,市场上有两个具有 QUALIFY
子句的 RDBMS(Snowflake 和 Teradata)类似于 WHERE
或 HAVING
子句,它们允许 window 函数成为过滤器的一部分。如果您使用的是这两个平台之一,那么您可以将其写为单个 SELECT 语句:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM employees
QUALIFY SALARY > AVG(SALARY) OVER ();
就像 WHERE
在执行开始时起作用,而 HAVING
在接近执行结束时起作用,QUALIFY
甚至比这更晚(就在 [=31= 之前) ]).奇怪的是,这正是您最初想要的,并且某些 RDBMS 预料到了您的需求。我希望更多的 RDBMS 在未来的版本中采用 QUALIFY 子句,因为它非常方便。
我写了这个查询
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM employees
WHERE SALARY > (SELECT AVG(SALARY)
FROM employees)
我有点困惑为什么我必须为它创建一个子查询,为什么我不能像这样写查询:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM employees
WHERE SALARY > AVG(SALARY)
SQL 是一种基于集合的语言。如果您只聚合一组中的一列,则必须聚合整个集合。您不能既聚合一个集合又不聚合一个集合。此外,SELECT
语句仅定义一个集合。因此,您无法在同一 SELECT 语句中将聚合集中的值与 non-aggregated 集(两组)中的值进行比较。
您的第一个语句有效,因为您有两个 SELECT 语句,每个语句都定义了一个不同的集合。一组通过 avg()
函数聚合,另一组保持 non-aggregated.
它也有效,因为聚合集是标量的(它只有一个值)。它可以将 non-aggregated 集中的每一行与 single-value 聚合集中保存的标量值进行比较。如果以非标量的方式定义聚合集,则会抛出错误,您将不得不通过 [=17] 中的 ON
子句在两个集合之间建立关系=] 在您的 FROM
子句中或通过相关的子查询。
另一个原因是操作顺序。通过 WHERE
子句的过滤首先发生在 SQL 的执行中。在过滤您的数据时,尚未发生其他操作。 GROUP BY/Aggregation 在 SQL 的执行中出现得很晚。因此,您试图将 SQL 中两个截然不同的步骤的结果相互比较。
操作顺序是HAVING
存在的原因。它与 WHERE
非常相似,但在聚合之后起作用。不过,这对您在此 SQL 中尝试做的事情没有帮助,因为您再次尝试将 non-aggregated 集合中的值与聚合集合中的值进行比较不能在单个 SELECT 语句中完成。
可能值得注意的是,您可以使用“window 函数”(也称为“有序分析函数”或“分析函数”)在 non-aggregated 集合内聚合 (so-to-speak) ") 大多数 RDBMS 都支持。
例如:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY, AVG(SALARY) OVER () as avg_salary
FROM employees;
这仍然会为 table employees
中的每一行吐出一个 non-aggregated 行。它将有第 4 列,其中每一行包含所有员工的平均工资。 每一行都包含相同的值。
+-------------+------------+------------+--------+------------+
| EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | avg_salary |
+-------------+------------+------------+--------+------------+
| 1 | bob | mcbob | 100 | 210 |
| 2 | sue | o'susan | 230 | 210 |
| 3 | venkat | van venkat | 300 | 210 |
+-------------+------------+------------+--------+------------+
也就是说,由于操作顺序的原因,您不能比较 WHERE
或 HAVING
子句中 window 函数的结果。 Window 函数逻辑几乎在 sql 执行的每一步之后运行。您只会得到一个不允许的错误。因此,您将再次需要两个 SELECT 语句:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM
(
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, SALARY, AVG(SALARY) OVER () as avg_salary
FROM employees;
) dt
WHERE SALARY > avg_salary;
最后,市场上有两个具有 QUALIFY
子句的 RDBMS(Snowflake 和 Teradata)类似于 WHERE
或 HAVING
子句,它们允许 window 函数成为过滤器的一部分。如果您使用的是这两个平台之一,那么您可以将其写为单个 SELECT 语句:
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM employees
QUALIFY SALARY > AVG(SALARY) OVER ();
就像 WHERE
在执行开始时起作用,而 HAVING
在接近执行结束时起作用,QUALIFY
甚至比这更晚(就在 [=31= 之前) ]).奇怪的是,这正是您最初想要的,并且某些 RDBMS 预料到了您的需求。我希望更多的 RDBMS 在未来的版本中采用 QUALIFY 子句,因为它非常方便。