在同一个 SELECT 列表中引用列别名

wiz*_*g64 43 postgresql select

我正在将旧的基于 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;
Run Code Online (Sandbox Code Playgroud)

当我在 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;
Run Code Online (Sandbox Code Playgroud)

有没有像第一个代码块那样的快捷方式来绕过复杂的嵌套?我也可以说100 * (samples.wet_weight / samples.dry_weight - 1) AS percent_water_100,但这只是我的代码中进行的更大的数学系统中的一个小例子,其中有数十个更复杂的数学位相互叠加。我宁愿尽可能干净地做而不重复自己。

Erw*_*ter 36

有时这很不方便,但它是 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;
Run Code Online (Sandbox Code Playgroud)

您可以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;
Run Code Online (Sandbox Code Playgroud)

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

  • 你好。您能否通过 SQL 标准防止歧义的示例来扩展您的答案? (6认同)

小智 6

我遇到了这样的事情,将 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 ;
Run Code Online (Sandbox Code Playgroud)

  • Postgres 中没有“交叉应用”。Postgres 坚持标准并使用“横向交叉连接”。 (5认同)
  • “CROSS APPLY”(和 OUTER APPLY)是 SQL Server 编写“LATERAL”子查询的方式。 (2认同)