如何在PostgreSQL中声明并使用临时表作为游标源?

如何在PostgreSQL中声明并使用临时表作为游标源?,postgresql,plpgsql,Postgresql,Plpgsql,在规范化了大部分2NF和一些3NF表之后,我现在需要下面这样的查询来上下移动我的表结构,以获取我需要的信息。PostgreSQL 9.3 CREATE TEMPORARY TABLE test AS With charts_on_date_of_service AS ( SELECT t.service_recid, t.tservice, t.chart_recid FROM ( select s.recid as service_recid, s.

在规范化了大部分2NF和一些3NF表之后,我现在需要下面这样的查询来上下移动我的表结构,以获取我需要的信息。PostgreSQL 9.3

CREATE TEMPORARY TABLE test  AS
With charts_on_date_of_service AS ( 
    SELECT t.service_recid, t.tservice, t.chart_recid           
    FROM  ( select s.recid as service_recid, s.tservice, p.chart_recid
        from doctorservices d                   
        join services s on (s.recid = d.service_recid)      
        join patients p on (p.recid = s.patient_recid)      
        where s.tservice::date = _tservice::date        
        ) as t 
)
select s.recid as service_recid, s.tservice, c.chart_recid, c.tservice as time_of_service
from charts_on_date_of_service  c                   
join patients p on (p.chart_recid = c.chart_recid)          
join services s on (s.patient_recid = p.recid)              
join doctorservices d  on ( d.service_recid = s.recid)          
where s.tservice::date <= _tservice::date               
order by c.chart_recid, s.tservice;                                    
由于涉及到这个查询,我不希望在plpgsql函数中重复它。也就是说,我想做一些类似的事情:

CREATE OR REPLACE FUNCTION test(_tservice timestamp)            
  RETURNS TABLE (service_recid bigint, chart_recid int, tservice timestamp, ct int) AS
$func$ 

DECLARE 

CREATE TEMPORARY TABLE test AS ....   <--THIS FAILS

cur CURSOR FOR
    SELECT t.service_recid, t.tservice, t.chart_recid   
    FROM   test t

BEGIN
      ... some processing commands on the temp table test and cursor cur....
END
我有几个相关的问题:

如何在plpgsql中声明临时表? 临时表可以用作游标的源吗? 创建一个临时表并在多个位置使用它会更好,还是在多个位置重新创建相同的查询会更好? 我似乎无法通过谷歌找到答案。
非常感谢您的任何帮助或想法

你必须使用不同的方法。在PL/pgSQL内部,任何CREATE语句都不能位于DECLARE部分。它和其他语句一样是语句,应该在函数体部分。若您可以在动态创建的表上进行迭代,则必须使用游标,并且必须在OPEN语句中指定查询,或者更好-用于循环:

这个例子是可行的,但是它非常昂贵,并且只有在必要时才应该使用这个模式。临时表很昂贵,如果您不需要它,就不要使用它。这有很好的理由:性能、复杂性,但通常不需要。来自T-SQL的一些模式不能在Postgres中使用,有些工作需要不同的思考。您可以使用数组、返回下一步、返回查询语句:

CREATE OR REPLACE FUNCTION test(a int)
RETURNS table (b int, c int, d int) AS $$
BEGIN
  RETURN QUERY SELECT col, col+1, col+2
                  FROM generate_series(1,a)
  RETURN;
END; $$ LANGUAGE plpgsql;
对于类似的普通函数,最好使用SQL语言:

CREATE OR REPLACE FUNCTION test(a int)
RETURNS table (b int, c int, d int) AS $$
  SELECT col, col+1, col+2
     FROM generate_series(1,a)
$$ LANGUAGE sql;
您可以在Postgres中使用数组:

CREATE OR REPLACE FUNCTION test(a int)
RETURNS TABLE (b int, c int, d int) AS $$
DECLARE cols int[];
BEGIN
  cols := ARRAY(SELECT generate_series(1,a));
  RETURN QUERY 
    SELECT col, col + 1, col + 2 
       FROM unnest(cols) g(col);
  RETURN;
END; $$ LANGUAGE plpgsql;

回答得很好。因此,如果临时表非常昂贵,在我的例子中,重复查询是否更好;我需要的两个游标各一次?谢谢。@Wayne,这取决于您的查询有多贵。临时表的成本随着频率的增加而增加-1/s(db+/-0),100/s(db)非常昂贵。始终取决于上下文,但行为与T-SQL有很大不同,内部实现也不同。如果有必要,可以使用临时表,但最好使用数组变量。
CREATE OR REPLACE FUNCTION test(a int)
RETURNS TABLE (b int, c int, d int) AS $$
DECLARE cols int[];
BEGIN
  cols := ARRAY(SELECT generate_series(1,a));
  RETURN QUERY 
    SELECT col, col + 1, col + 2 
       FROM unnest(cols) g(col);
  RETURN;
END; $$ LANGUAGE plpgsql;