Why can't I use column aliases in the next SELECT expression?
Can I modify the next to use the column aliases avg_time
and cnt
in an expression ROUND(avg_time * cnt, 2)
?
SELECT
COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time,
MAX(time) as max_time,
ROUND(AVG(time), 2) as avg_time,
MIN(time) as min_time,
COUNT(path) as cnt,
ROUND(avg_time * cnt, 2) as slowdown, path
FROM
loadtime
GROUP BY
path
ORDER BY
avg_time DESC
LIMIT 10;
It raises the next error:
ERROR: column "avg_time" does not exist
LINE 7: ROUND(avg_time * cnt, 2) as slowdown, path
The next, however, works fine (use primary expressions instead of column aliases:
SELECT
COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time,
MAX(time) as max_time,
ROUND(AVG(time), 2) as avg_time,
MIN(time) as min_time,
COUNT(path) as cnt,
ROUND(AVG(time) * COUNT(path), 2) as slowdown, path
FROM
loadtime
GROUP BY
path
ORDER BY
avg_time DESC
LIMIT 10;
Solution 1:
You can use a previously created alias in the GROUP BY
or HAVING
statement but not in a SELECT
or WHERE
statement. This is because the program processes all of the SELECT
statement at the same time and doesn't know the alias' value yet.
The solution is to encapsulate the query in a subquery and then the alias is available outside.
SELECT stddev_time, max_time, avg_time, min_time, cnt,
ROUND(avg_time * cnt, 2) as slowdown
FROM (
SELECT
COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time,
MAX(time) as max_time,
ROUND(AVG(time), 2) as avg_time,
MIN(time) as min_time,
COUNT(path) as cnt,
path
FROM
loadtime
GROUP BY
path
ORDER BY
avg_time DESC
LIMIT 10
) X;
Solution 2:
The order of execution of a query (and thus the evaluation of expressions and aliases) is NOT the same as the way it is written. The "general" position is that the clauses are evaluated in this sequence:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Hence the column aliases are unknown to most of the query until the select clause is complete (and this is why you can use aliases in the ORDER BY clause). However table aliases which are established in the from clause are understood in the where to order by clauses.
The most common workaround is to encapsulate your query into a "derived table"
Suggested reading: Order Of Execution of the SQL query
Note: different SQL dbms have different specific rules regarding use of aliases
EDIT
The purpose behind reminding readers of the logical clause sequence is that often (but not always) aliases only becomes referable AFTER the clause where the alias is declared. The most common of which is that aliases declared in the SELECT
clause can be used by the ORDER BY
clause. In particular, an alias declared in a SELECT
clause cannot be referenced within the same SELECT
clause.
But please do note that due to differences in products not every dbms will behave in this manner