Why can't I use an alias for an aggregate in a having clause?

SqlSql Server-2008

Sql Problem Overview


My code is like shown below :

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

My code causes the error "Invalid column name 'col7' ". Why does this happen ? It seems illogical that SQL does not allow me to use col7 in the last line.

I am using SQL server express 2008

Sql Solutions


Solution 1 - Sql

The HAVING clause is evaluated before the SELECT - so the server doesn't yet know about that alias.

  1. First, the product of all tables in the FROM clause is formed.

  2. The WHERE clause is then evaluated to eliminate rows that do not satisfy the search_condition.

  3. Next, the rows are grouped using the columns in the GROUP BY clause.

  4. Then, groups that do not satisfy the search_condition in the HAVING clause are eliminated.

  5. Next, the expressions in the SELECT statement target list are evaluated.

  6. If the DISTINCT keyword in present in the select clause, duplicate rows are now eliminated.

  7. The UNION is taken after each sub-select is evaluated.

  8. Finally, the resulting rows are sorted according to the columns specified in the ORDER BY clause.

  9. TOP clause is executed.

Hope this answers your question. Also, it explains why the alias works in ORDER BY clause.

Solution 2 - Sql

In MS SQL, the only place (I'm aware of) that you can reference aliases is in the ORDER BY clause. The ability to reference aliases in other parts of the query is a feature that many other db platforms have and honestly it annoys me that Microsoft hasn't considered it a useful enough feature to add it.

Solution 3 - Sql

Try with this one as the select list contains the same expression you can use in having clause also:

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

Solution 4 - Sql

You should select twice to use the count() column

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

Solution 5 - Sql

U can use this code:

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

Solution 6 - Sql

You can solve this by using a nested query.

I have also run into this problem when I am wanting to improve performance. I have needed to run a count() based on certain fields within a JSON field in a table, obviously we would want to parse JSON only once instead of having to include a separate count in a where or have clause (especially an expensive one like in my case).

If col1 is a unique id, the most computationally efficient way could be to nest the count in a separate 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;

This way the count is only ran once, creating a sort of temporary lookup table for reference by the rest of your query.

Again, this only works if col1 is unique for every record, which normally isn't too much to ask since most tables have some sort of id primary key.

Solution 7 - Sql

select col1,count(col2) as col7 from --some join operation group by col1 having count(col2) >= 3;

Honestly I am miffed as to why SQL Server does not process the column alias. I use this as a workaround. It still prints the column name as your alias but processes using the original aggregate function.

Solution 8 - Sql

In SQL the execution flow of clause is, From --> where --> group by --> having --> select --> order by --> distinct --> top.

Since alias where declared in select clause so it is not available for clauses which is executed before select ( it's available for clauses which are executing only after select ) But there is another way to use alias, by using nested select Eg: select * from (select name, salary, salary+1000 as hike from employee ) as emp where hike > 10000;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsky scraperView Question on Stackoverflow
Solution 1 - SqlkrishnaView Answer on Stackoverflow
Solution 2 - SqlBrandon MooreView Answer on Stackoverflow
Solution 3 - SqlPratikView Answer on Stackoverflow
Solution 4 - SqlJunnan WangView Answer on Stackoverflow
Solution 5 - Sqlali khezriView Answer on Stackoverflow
Solution 6 - SqlBroperView Answer on Stackoverflow
Solution 7 - SqlPearl PuriView Answer on Stackoverflow
Solution 8 - SqlMeganView Answer on Stackoverflow