我正在将旧的基于MS-Access的系统转换为PostgreSQL。在Access中,由SELECT组成的字段可以用作以后字段的方程式的一部分,例如:

错误:


错误:列“ percent_water”不存在。


这里是我可以通过从子选择:

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


在第一个代码块中是否有某种捷径可以绕开复杂的嵌套?我也可以说100 * (samples.wet_weight / samples.dry_weight - 1) AS percent_water_100,但这只是我的代码中运行着一个更大的数学系统的一个小例子,数十个更复杂的数学部分相互叠加。我宁愿尽可能干净地做,不要重复自己。

#1 楼

有时不方便,但这是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;



https://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.3#LATERAL_JOIN
如何基于查找表检索最接近的值?

我添加了NULLIF()来防止被零除错误。

评论


你好您是否可以通过一个示例来扩展答案,该示例可以消除SQL标准的歧义?

– Eugen Konkov
19 Mar 7 '19 at 8:26

#2 楼

我遇到了类似这样的事情:将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 ;


评论


CROSS APPLY(和OUTER APPLY)是SQL Server编写LATERAL子查询的方式。

–超立方体ᵀᴹ
16年11月1日在22:17

Postgres中没有交叉应用。 Postgres坚持标准,并使用横向交叉连接。

– a_horse_with_no_name
16年11月1日在22:25