在同一查询中使用不止一次计算的列



我有一个反复出现的问题,我想在选择查询中计算的值不止一次。这是一个示例

SELECT
  complicated_function(x) as foo,
  another_complicated_function(y) as bar,
  complicated_function(x)/another_complicated_function(y) as foo_bar_rate
FROM my_table;

编写此查询的最简单方法是什么?理想情况下,我想写

SELECT
  complicated_function(x) as foo
  another_complicated_function(y) as bar,
  foo/bar as foo_bar_rate
FROM my_table;

这个问题与计算的特定值无关,而是关于如何以更简单的方式编写此查询的方式。

您可以使用WITH

WITH computed_functions as (
  SELECT
    complicated_function(x) as foo,
    another_complicated_function(y) as bar,
  FROM my_table;
)
SELECT foo, bar, foo/bar as foo_bar_rate FROM computed_functions;

但是这仍然很笨拙。如果要选择更多列,则需要将其添加到使用查询和主查询中。

使用CTE的答案通常很好。但是,有几个建议:

SELECT *, foo / NULLIF(bar, 0) AS foo_bar_rate  -- defend against div0
FROM  (
   SELECT complicated_function(x)         AS foo
        , another_complicated_function(y) AS bar
   FROM   my_table
   --  OFFSET 0  -- see below
   ) sub;
  • 一个CTE(尽管更容易阅读到某些(通常比Postgres中的普通子查询更昂贵。如果性能是相关的,则仅在实际需要的地方使用CTE。在这种情况下,您不会。

    Postgres可能会在其查询计划中弄平子查询,如果成本设置和服务器配置很好,通常也是最好的操作方案。如果您知道更好(您确定?(,则可以使用未记录的"查询提示" OFFSET 0 ,这是逻辑上的噪声,但强制迫使子查询单独执行。

    • 如何防止Postgres插入子查询?
  • 要使代码短,您可以在外部选择中使用 SELECT * 。(由于您抱怨,因此必须将所有列添加到主查询中。(

  • 使用 nullif(bar,0(通过0 例外来防御可能的划分 - 除非another_complicated_function(y)永远无法返回0

最新更新