【问题标题】:Use computed columns more than once in same query在同一个查询中多次使用计算列
【发布时间】:2017-06-02 18:49:37
【问题描述】:

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

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;

这个问题不是关于正在计算的特定值,而是关于如何以更简单的方式编写这个查询,更容易维护。

【问题讨论】:

  • 请提供一个表定义(CREATE TABLE 语句)显示数据类型和约束以及您的 Postgres 版本。并解释你在准确地计算什么。可能有一个更简单/更快的解决方案。而且至少有一个挥之不去的错误。
  • 这个问题与我正在计算的具体值无关。我重写了查询以反映这一点。我正在尝试编写更好更易于维护的 SQL。我正在使用 PostgreSQL 9.6.2

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


【解决方案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 查询和主查询中。

【讨论】:

    【解决方案2】:

    您使用 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

    【讨论】:

      猜你喜欢
      • 2013-07-01
      • 2012-09-23
      • 1970-01-01
      • 2019-11-23
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多