PostgreSQL 中 WITH .. AS .. 子句的替代方法

Alternatives to WITH .. AS .. clause in PostgreSQL

我有几个以下类型的大查询(为清楚起见进行了简化)。

create function myfunction()
  returns void
as $$
begin

...
with t as (
  total                 as total,
  total * 100 / total   as total_percent,
  total / people.count  as total_per_person,
  part1                 as part1,
  part1 * 100 / total   as part1_percent,
  part1 / people.count  as part1_per_person,
  part2                 as part2,
  part2 * 100 / total   as part2_percent,
  part2 / people.count  as part2_per_person,
  ...
  from (
    select
    total.amount as total
    part1.amount as part1
    part2.amount as part2
    ...
    people.amount as people
    from (select ...from mytable..) total
    left join (select ...from mytable..) part1 on ...
    left join (select ...from mytable..) part2 on ...
    ...
    left join (select ...from mytable..) people on ...
  ) r
)

insert into another_table  -- << NOW I NEED TO REPLACE THIS WITH "RETURN QUERY"
        select .., total             from t
  union select .., total_percent     from t
  union select .., total_per_person  from t
  union select .., part1             from t
  union select .., part1_percent     from t
  union select .., part1_per_person  from t
  union select .., part2             from t
  union select .., part2_percent     from t
  union select .., part2_per_person  from t
  ...

...
$$ language plpgsql;

它这么大的原因是大多数列都是从其他列派生的。查询旨在最大程度地减少拉取数据和聚合的重复,从而最大限度地减少 运行 时间(因为此查询到 运行 大约需要 10 秒,因为 mytable 仅超过 400 万行)。所有 15 列都插入 another_table 并结合联合运算符。

with .. as .. 子句非常适合这种情况。但是现在,重构程序,我必须将生成的数据集交给另一个函数进行 post 处理(而不是插入到 another_table 中)。

所以,我不得不用 return query 替换 insert into another_table,但 WITH .. AS .. 不喜欢那样。

换句话说,这是我试图达到的更新功能(它不起作用 - 解释器在 with .. as 块之后不期望 return query):

create function myfunction()
  returns setof data -- << now returning a data set
as $$
begin

...
with t as (
  --SAME QUERY
  ) r
)

return query  -- << line that is changed
    -- SAME SELECT HERE
...
$$ language plpgsql;

现在我的问题是,WITH .. AS .. 有哪些替代方案?所以,我可以用它来使用 return query 。我打算尝试使用临时表,但我仍然很好奇如何重写用 with .. as ....

编写的查询

问题中的查询有几个明显的废话部分。由于之前已经执行过,我假设人工简化的工件?
喜欢:total * 100 / total 将毫无意义,因为它会燃烧成 100.
或者:没有连接条件的连接,这是简单的语法错误。

除此之外,RETURN QUERY 不是 SQL 而是 PL/pgSQL 命令:

  • How to return result of a SELECT inside a function in PostgreSQL?

您可能忘记提及 PL/pgSQL 代码块,或者您正试图对 SQL.

使用无效语法

在 PL/pgSQL 中,如果将 RETURN QUERY 放在 查询 SQL 之前,这将起作用(除了明显的语法错误), CTE (Common Table Expression) - 这是 WITH 子句的规范名称 - 是 SQL 语句的一部分 :

RETURN QUERY        -- plpgsql command
WITH  t AS ( ... )  -- here starts the SQL query
SELECT .., total                 FROM t
UNION SELECT .., total_percent   FROM t
UNION SELECT.., total_per_person FROM t
-- etc.

在做的时候,最后一部分很可能是错误的。我很确定你想要 UNION ALL,而不是 UNION,后者会折叠结果中的任何重复项。

更好的是,在 LATERAL 连接中使用带有 VALUES 表达式的智能技术来“反透视”您的长行:

...
SELECT t1.*
FROM   t, LATERAL (
   VALUES
       (.., t.total)   -- whatever you may be hiding behind ".."
     , (.., t.total_percent)
     , (.., t.total_per_person)
     , (.., t.part1)
     , (.., t.part1_percent)
       -- etc.
   ) t1 ("name_for ..", total);

应该更短更便宜。在 dba.SE

上的相关回答中,这个想法归功于@Andriy