在同一查询中多次使用计算列

时间:2017-06-02 18:49:37

标签: sql postgresql subquery common-table-expression divide-by-zero

我有这个反复出现的问题,我希望在select查询中多次使用我计算的值。这是一个例子

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;

这个问题不是关于计算的具体值,而是关于如何以更简单的方式编写此查询,以便更容易维护。

2 个答案:

答案 0 :(得分:1)

您可以使用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;

然而,这仍然是笨重的。如果要选择更多列,则需要将其添加到WITH查询和主查询。

答案 1 :(得分:1)

使用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 ,这是逻辑噪音,但强制单独执行子查询。

  • 为了缩短代码,您可以在外部SELECT中使用 SELECT * 。 (由于您抱怨,您必须将所有列添加到主查询中。)

  • 使用NULLIF(bar, 0)防止可能的除以0 例外 - 除非another_complicated_function(y)永远不会返回0