Почему я не могу использовать псевдонимы столбцов в следующем выражении SELECT?
Могу ли я изменить следующий, чтобы использовать псевдонимы столбца avg_time
а также cnt
в выражении 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;
Возникает следующая ошибка:
ERROR: column "avg_time" does not exist
LINE 7: ROUND(avg_time * cnt, 2) as slowdown, path
Следующий, однако, работает нормально (используйте первичные выражения вместо псевдонимов столбцов:
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;
4 ответа
Вы можете использовать ранее созданный псевдоним в GROUP BY
или же HAVING
но не в SELECT
или же WHERE
это потому, что инструкция обрабатывает все части SELECT
в то же время и запрос еще не знает это значение.
Решение заключается в инкапсуляции запроса в подзапросе, а затем псевдоним доступен снаружи.
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;
Порядок выполнения запроса НЕ совпадает с тем, как он написан. "Общая" позиция заключается в том, что предложения оцениваются в следующей последовательности:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Следовательно, псевдонимы столбцов неизвестны большинству запросов до тех пор, пока предложение select не будет завершено (и поэтому вы можете использовать псевдонимы в предложении ORDER BY). Однако псевдонимы таблиц, которые установлены в предложении from, понимаются в разделах, где можно упорядочить.
Наиболее распространенным обходным решением является инкапсуляция вашего запроса в "производную таблицу".
Рекомендуемое прочтение: порядок выполнения SQL-запроса
Примечание: разные базы данных SQL имеют разные конкретные правила относительно использования алисов
Псевдонимы недоступны до тех пор, пока виртуальное отношение фактически не будет создано. Если вы хотите создать дополнительные выражения, используя сами псевдонимы, вам нужно будет создать виртуальное отношение, используя в качестве подзапроса, а не выполнять дополнительный запрос поверх него. Поэтому я бы изменил ваш запрос следующим образом:
SELECT stddev_time, max_time, avg_time, min_time, ROUND(avg_time * cnt, 2) as slowdown, path 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,
ROUND(AVG(time) * COUNT(path), 2) as slowdown, path
FROM
loadtime
GROUP BY
path
ORDER BY
avg_time DESC
LIMIT 10;
)
Я хочу добавить здесь причину, по которой ваш второй запрос работал, потому что планировщик запросов распознал эти столбцы, как определено непосредственно в таблице, из которой вы их запрашиваете.
Либо повторить выражения:
ROUND(ROUND(AVG(time), 2) * COUNT(path), 2) as slowdown
или используйте подзапрос:
SELECT *, 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) x
ORDER BY avg_time DESC
LIMIT 10;