PostgreSQL:在同一查询中使用计算列

use*_*150 46 sql postgresql calculated-columns

我在postgres中使用计算列时遇到问题.下面给出了一个在SQL中工作的类似代码,是否可以重新创建它PostgreSQL

select cost_1, quantity_1, cost_2, quantity_2, 
      (cost_1 * quantity_1) as total_1,
      (cost_2 * quantity_2) as total_2,
      (calculated total_1 + calculated total_2) as total_3
from data;
Run Code Online (Sandbox Code Playgroud)

PostgreSQL类似的代码中返回错误:

列total_1和total_2不存在.

a_h*_*ame 47

您需要将SELECT语句包装到派生表中,以便能够访问列别名:

select cost1,
       quantity_1,
       cost_2,
       quantity_2
       total_1 + total_2 as total_3
from (
    select cost_1, 
           quantity_1, 
           cost_2, 
           quantity_2, 
           (cost_1 * quantity_1) as total_1,
           (cost_2 * quantity_2) as total_2
    from data
) t
Run Code Online (Sandbox Code Playgroud)

对此不会有任何性能损失.

(我真的惊讶你的原始SQL语句在DBMS中运行)

  • 原始帖子看起来像SAS的PROC SQL,它允许这样做 (4认同)
  • @Davita:在 Postgres 中,CTE 的优化方式与派生表不同。在大多数情况下(包括这种情况),这没有什么区别,所以这可以归结为个人喜好。而且,并不是每个人都习惯 CTE,这会在我想避免的答案中引入另一个级别的“复杂性”。 (4认同)

Luk*_*zda 31

如果你不喜欢用outerquery包装整个查询,你可以LATERAL用来计算中间数total_1total_2:

SELECT cost_1, quantity_1, cost_2, quantity_2, total_1, total_2,
       total_1 + total_2 AS total_3
FROM data
,LATERAL(SELECT cost_1 * quantity_1, cost_2 * quantity_2) AS s1(total_1,total_2);
Run Code Online (Sandbox Code Playgroud)

DBFiddle演示

输出:

?????????????????????????????????????????????????????????????????????????????????
? cost_1  ? quantity_1  ? cost_2  ? quantity_2  ? total_1  ? total_2  ? total_3 ?
?????????????????????????????????????????????????????????????????????????????????
?      1  ?          2  ?      3  ?          4  ?       2  ?      12  ?      14 ?
?      3  ?          5  ?      7  ?          9  ?      15  ?      63  ?      78 ?
?     10  ?          5  ?     20  ?          2  ?      50  ?      40  ?      90 ?
?????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

  • 不错哦.TIL.对于某些情况来说,这是非常好的,包括我创建了一个视图,可以对以前的计算进行多层参考.内嵌重复计算容易出错,嵌套子查询对我来说有9个嵌套级别."LATERAL"版本更易于遵循和维护. (2认同)
  • @RobinNemeth `s1` 是派生表的别名。您可以在“SELECT”中使用它,例如“SELECT s1.total_1 + s1.total_2 AS total_3” (2认同)

Man*_*ngo 12

通常,您需要了解有关该SELECT条款的两件事:

  • 虽然它是首先编写的,但它是最后一次评估,但该ORDER BY条款除外.这就是为什么你不能在任何其他子句(特别是该WHERE子句)中使用任何计算字段或别名,除非在该ORDER BY子句中.
  • SELECT子句中的计算是并行执行的,或者至少按照它们的方式进行处理.这就是为什么你不能将一个计算作为另一个计算的一部分.

所以,简短的回答是,你不能,这是设计的.

值得注意的例外是Microsoft Access,您可以在后续列和WHERE子句中使用计算.然而,虽然这很方便,但它实际上并不是一个优点:不遵循上述原则效率较低.但是对于轻型数据库来说这是可以的,这就是Access应该用于的.

如果您确实想要重复使用计算结果,则需要以子查询或公用表表达式的形式单独查询.CTE更易于使用,因为它们更易于阅读.

编辑

在不改变原始答案的要点的情况下,我想我可能会补充一点,我认为这种解释可能有点意味深长.

现代DBMS在计划和优化查询方面投入了大量精力,因此,如果查询确实以特定顺序执行,则不再正确.据我所知,没有技术上的原因,为什么优化器无法向前看并将计算结果合并到解析查询中,即使它只是替换表达式.

那好吧 …


tpo*_*eux -5

您尝试在表达式中使用列别名。如果一个系统允许你这样做,那它只是语法糖。这应该适用于任何 SQL 方言。

select 
 cost_1
,quantity_1
,cost_2
,quantity_2
,cost_1 * quantity_1 as total_1
,cost_2 * quantity_2 as total_2
,(cost_1 * quantity_1) + (cost_2 * quantity_2) as total_3 

from data;
Run Code Online (Sandbox Code Playgroud)