PostgreSQL中WITH .. AS ..子句的替代品

时间:2015-06-19 22:15:05

标签: sql postgresql plpgsql common-table-expression postgresql-9.3

我有以下类型的几个大查询(为简洁起见,已简化)。

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个列都插入到另一个表中,并与union运算符结合使用。

with .. as ..条款对此方案起到了很好的作用。但是现在,重构程序,我必须将生成的数据集交给另一个函数进行后期处理(而不是插入到another_table中)。

所以,我必须将insert into another_table替换为return query,但WITH .. AS ..不喜欢这样。

换句话说,这是我想要达到的更新功能(这不起作用 - 解释器在return query阻止后不期望with .. as

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 ...编写的查询。

1 个答案:

答案 0 :(得分:2)

问题中的查询有几个明显无意义的部分。既然您之前一直在执行它,我认为这些都是手工简化的工件? 比如: total * 100 / total 会毫无意义,因为它会烧毁到100。 或者:没有连接条件的连接,这是普通的语法错误。

除此之外, RETURN QUERY 不是SQL而是plpgsql命令:

要么你忽略了提到你正在使用带有plpgsql代码的functionDO语句,要么你试图使用无效的SQL语法。

plpgsql 中,如果您在 SQL查询之前放置RETURN QUERY CTE (Common Table Expression) - 那&# 39;是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,它会在结果中折叠任何重复项。

更好的是,使用这种智能技术,在VALUES加入LATERAL表达式中使用... 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); 表达式来反对&#34;反向转动&#34;你的长行:

f = lambda x: x.prod() - 1 # cumulative product of all returns ("gret": 1+ret) in each week for each firm
weekly_rets = df.groupby('PERMNO').resample('W-WED', closed='left', how=f)

应该大大缩短和便宜。在dba.SE

的相关答案中向@Andriy提出这个想法