I have the following script
SELECT
CASE
WHEN Grade < 4
THEN 'Fail'
WHEN Grade >=4 and Grade < 6
THEN 'C'
WHEN Grade >=6 and Grade < 8
THEN 'Ok'
ELSE 'Exc.'
END AS [Status],
COUNT(Grade) AS v
FROM
GradeList
GROUP BY
[Status]
And it doesn't see the column Status
. Can't get why, what's the problem
CodePudding user response:
That is how SQL Server (and SQL) are defined. Column aliases defined in the SELECT
are not available in the FROM
, WHERE
, or GROUP BY
clauses.
There are multiple solutions for this. My favorite is to use APPLY
because this defines the aliases in the FROM
clause:
SELECT v.Status, COUNT(*) as v
FROM GradeList gl CROSS APPLY
(VALUES (CASE WHEN Grade < 4 THEN 'Fail'
WHEN Grade < 6 THEN 'C'
WHEN Grade < 8 THEN 'Ok'
ELSE 'Exc.'
END)
) v(Status)
GROUP BY v.Status;
Note that this also simplifies the CASE
logic. The first matching condition is returned, so there is no need for BETWEEN
. That actually makes it much easier to add and remove conditions, if you want to tweak the query.
CodePudding user response:
SQL Server processes the SQL Statment in a particular logical order. As SELECT clause comes after GROUP BY clause, GROUP BY clause does not see the column alias.
Read more on the logical processing order on MSDN
- FROM
- ON
- JOIN
- WHERE
- GROUP BY
- WITH CUBE or WITH ROLLUP
- HAVING
- SELECT
- DISTINCT
- ORDER BY
- TOP
You can go for derived table or Common Table Expression to get over this problem.
SELECT Status, COUNT(Grade) AS v
FROM
(
SELECT
CASE
WHEN Grade < 4
THEN 'Fail'
WHEN Grade >=4 and Grade < 6
THEN 'C'
WHEN Grade >=6 and Grade < 8
THEN 'Ok'
ELSE 'Exc.'
END AS [Status],
Grade
FROM
GradeList
) AS g(Status,Grade)
GROUP BY
[Status]
;WITH cte_gradelist(Status,Grade) AS
(
SELECT
CASE
WHEN Grade < 4
THEN 'Fail'
WHEN Grade >=4 and Grade < 6
THEN 'C'
WHEN Grade >=6 and Grade < 8
THEN 'Ok'
ELSE 'Exc.'
END AS [Status],
Grade
FROM
GradeList
)
SELECT Status, COUNT(Grade) AS v
FROM cte_gradelist
GROUP BY
[Status]