同一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会引发错误:

错误:列“ percent_water”不存在。

通过从子选择中进行选择,这是解决该问题的方法:

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,但这只是我的代码中运行着一个更大的数学系统的一个小例子,数十个更复杂的数学部分相互叠加。我宁愿尽可能干净地做而不重复自己。

Answers:


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标准的歧义?
Eugen Konkov

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)是SQL Server编写LATERAL子查询的方式。
ypercubeᵀᴹ

4
cross applyPostgres中没有。Postgres遵循标准并使用cross join lateral
a_horse_with_no_name
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.