为什么我不能在having 子句中使用聚合的别名?

问题描述 投票:0回答:9

我的代码如下所示:

select col1,count(col2) as col7
from --some join operation
group by col1
having col7 >= 3 -- replace col7 by count(col2) to make the code work

我的代码导致错误“无效的列名'col7'”。为什么会出现这种情况? SQL不允许我在最后一行使用col7,这似乎不合逻辑。

我正在使用 SQL Server Express 2008

sql sql-server-2008
9个回答
81
投票

HAVING
子句在
SELECT
之前评估 - 因此服务器尚不知道该别名。

  1. 首先,形成

    FROM
    子句中所有表的乘积。

  2. 然后评估
  3. WHERE

    子句以消除不满足 search_condition 的行。

    
    

  4. 接下来,使用
  5. GROUP BY

    子句中的列对行进行分组。

    
    

  6. 然后,排除不满足
  7. search_condition

    子句中

    HAVING
    的组。
    
    

  8. 接下来,对
  9. SELECT

    语句目标列表中的表达式进行求值。

    
    

  10. 如果 select 子句中存在
  11. DISTINCT

    关键字,重复行现在将被消除。

    
    

  12. UNION

    是在评估每个子选择后获取的。

    
    

  13. 最后,结果行根据
  14. ORDER BY

    子句中指定的列进行排序。

    
    

  15. TOP

    子句被执行。

    
    

  16. 希望这能回答您的问题。此外,它还解释了为什么别名在
ORDER BY

子句中起作用。

    


36
投票


11
投票

select * from (select col1,count(col2) as col7 from --some join operation group by col1) as temp where temp.col7 >= 3



8
投票

SELECT COL1,COUNT(COL2) AS COL7 FROM --SOME JOIN OPERATION GROUP BY COL1 HAVING COUNT(COL2) >= 3



4
投票

由于别名在 select 子句中声明,因此它不适用于在 select 之前执行的子句(它适用于仅在 select 之后执行的子句) 但还有另一种使用别名的方法,即使用嵌套选择 例如: select * from (选择姓名、工资、工资+1000 作为员工的加薪) as emp where加薪 > 10000;


1
投票

IF OBJECT_ID('tempdb..#temp') is not null DROP TABLE #temp -- Create tempurary table CREATE TABLE #temp (Id BIGINT IDENTITY(1,1), col1 BIGINT, countOfcol2 BIGIN) --insert from the table 2 #temp INSERT INTO #temp (col1,countOfcol2) select col1,count(col2) as col7 from --some join operation select col1,countOfcol2 from #temp group by col1 having countOfcol2 >= 3 -- replace col7 by count(col2) to make the code work



1
投票

当我想提高性能时,我也遇到了这个问题。我需要根据表中 JSON 字段中的某些字段运行

count()

,显然我们只想解析 JSON 一次,而不必在

where
have
子句中包含单独的计数(尤其是像我这样的昂贵的)。

如果

col1

是唯一的 id,计算效率最高的方法可能是将计数嵌套在单独的

select
select col1, innerquery.col7 from whatevertable inner join (select col1, count(col2) as col7 from whatevertable group by col1) as innerquery on innerquery.col1 = whatevertable.col1 where innerquery.col7 >= 3;

这样计数仅运行一次,创建一种临时查找表以供其余查询参考。

再次强调,这仅在

col1

对于每条记录都是唯一的情况下才有效,这通常不会有太多要求,因为大多数表都有某种 id 主键。

    


0
投票
count(col2)

>= 3; 老实说,我很恼火为什么 SQL Server 不处理列别名。我用这个作为解决方法。它仍然打印列名作为别名,但使用原始聚合函数进行处理。


0
投票
onecompiler.com

进行的非科学测试,该测试为多个 RDBMS(和非 SQL DBMS)提供浏览器接口: CREATE TABLE EMPLOYEE ( empId INTEGER PRIMARY KEY, name VARCHAR(30) NOT NULL, dept VARCHAR(30) NOT NULL, salary INT NOT NULL ); INSERT INTO EMPLOYEE VALUES (0001, 'Clark', 'Sales', 10000); INSERT INTO EMPLOYEE VALUES (0002, 'Dave', 'Accounting', 20000); INSERT INTO EMPLOYEE VALUES (0003, 'HAL', 'Accounting', 12000); INSERT INTO EMPLOYEE VALUES (0004, 'Ava', 'Sales', 30000); INSERT INTO EMPLOYEE VALUES (0005, 'Johnny', 'Sales', 15000); -- using alias SELECT dept, AVG(salary) AS avg_sal FROM EMPLOYEE GROUP BY dept HAVING avg_sal > 17000 -- using aggregate function spelled out twice SELECT dept, AVG(salary) AS avg_sal FROM EMPLOYEE GROUP BY dept HAVING AVG(salary) > 17000

以下 RDBMS 接受 
HAVING

子句中的“别名”:


PostgreSQL 14.11:否
  • MySQL 8.0.27:是
  • MariaDB 10.7.8:是
  • Microsoft SQL Server 2022 (RTM-CU12):否
  • SQLite 3.27.2:是
  • 如何确定版本:

PostgreSQL:
    SELECT version()
  • MySQL:
  • SELECT version()
  • MariaDB:
  • SELECT version()
  • MS SQLServer:
  • Select @@version
  • SQLite:
  • SELECT sqlite_version();
  • 
        
© www.soinside.com 2019 - 2024. All rights reserved.