Ссылочный столбец псевдоним в том же списке SELECT

27

Я конвертирую старую систему на основе MS-Access в PostgreSQL. В Access поля, которые были созданы в SELECT, могут использоваться как части уравнений для более поздних полей, например:

SELECT
    samples.id,
    samples.wet_weight / samples.dry_weight - 1 AS percent_water,
    100 * percent_water AS percent_water_100
FROM samples;

Когда я делаю это в PostgreSQL, Postgres выдает ошибку:

ОШИБКА: столбец «процент_воды» не существует.

Вот как я могу обойти это, выбрав из подвыбора:

SELECT
    s1.id,
    s1.percent_water,
    100 * s1.percent_water AS percent_water_100
FROM (
    SELECT
        samples.id,
        samples.wet_weight / samples.dry_weight - 1 AS percent_water
    FROM samples
    ) s1;

Есть ли какой-нибудь ярлык, как в первом блоке кода, чтобы обойти сложное вложение? Я мог бы также просто сказать 100 * (samples.wet_weight / samples.dry_weight - 1) AS percent_water_100, но это всего лишь небольшой пример из того, что в моем коде происходит намного более крупная математическая система, когда десятки более сложных математических элементов расположены друг над другом. Я бы предпочел сделать как можно более чисто, не повторяясь.

wizpig64
источник

Ответы:

24

Иногда это неудобно, но это стандартное поведение SQL, и оно предотвращает неоднозначности. Вы не можете ссылаться на псевдонимы столбцов в том же SELECTсписке.

Есть более короткие синтаксические опции:

SELECT s.*, s.percent_water * 100 AS percent_water_100
FROM  (
   SELECT id, wet_weight / NULLIF(dry_weight - 1, 0) AS percent_water
   FROM   samples
   ) s;

И вы можете использовать LATERALобъединение в Postgres 9.3+:

SELECT s.id, s1.percent_water
     , s1.percent_water * 100 AS percent_water_100
FROM   samples s
     , LATERAL (SELECT s.wet_weight / NULLIF(s.dry_weight - 1, 0) AS percent_water) s1;

Я добавил, NULLIF()чтобы защитить от ошибок деления на ноль.

Эрвин Брандштеттер
источник
2
Здравствуй. Можете ли вы расширить свой ответ примером, который предотвращает неоднозначность стандарта SQL?
Евгений Коньков
4

Я столкнулся с чем-то вроде этого, перенеся 500-строчный запрос Netezza (или модифицированный Postgres) на SQL Server. В Netezza вычисленный псевдоним столбца было разрешено использовать в качестве значения в последующих ссылках.

Моя работа заключалась в том, чтобы использовать CROSS APPLY с коррелированным подзапросом. Прелесть этого в том, что многочисленные ссылки на псевдоним столбца в исходном запросе вообще не нужно было менять.

Используя запрос из OP, CROSS APPLYметод будет выглядеть примерно так:

SELECT
    s.id,
    x.percent_water,
    100 * x.percent_water AS percent_water_100
FROM samples AS s
CROSS APPLY (SELECT s.wet_weight / s.dry_weight - 1 AS percent_water ) x ;
Д Турпин
источник
1
CROSS APPLY(и OUTER APPLY) - это способ написания LATERALподзапросов для SQL Server .
ypercubeᵀᴹ
4
Там нет cross applyв Postgres. Postgres придерживается стандарта и использует cross join lateral.
a_horse_with_no_name