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

时间:2016-01-08 05:12:15

标签: 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.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中“声明”临时表?
  • 临时表可以用作游标的源吗?
  • 是否可以更好地创建单个临时表并在多个位置使用它,或者更好地在多个位置重新创建相同的查询?

我似乎无法找到谷歌的答案。 非常感谢任何帮助或想法。

1 个答案:

答案 0 :(得分:4)

你必须使用不同的方法。在PL / pgSQL中,任何CREATE语句都不能在DECLARE部分。它是任何其他声明,应该在功能体部分。如果您可以迭代动态创建的表,则必须使用unbound游标,并且必须在OPEN语句中指定查询(或更好 - 使用FOR周期):

CREATE OR REPLACE FUNCTION test(a int)
RETURNS TABLE (b int, c int, d int) AS $$
BEGIN
  DROP TABLE IF EXISTS foo; 
  CREATE TEMP TABLE foo(col int);
  INSERT INTO foo SELECT generate_series(1,a);
  FOR b, c, d IN SELECT col, col + 1, col + 2 FROM foo
  LOOP
    RETURN NEXT;
  END LOOP;
END; $$ LANGUAGE plpgsql;

此示例有效,但非常昂贵,只有在必要时才应使用 。临时表很昂贵,如果你不需要它,就不要使用它(有很好的理由:性能,复杂性,但通常没有必要)。 T-SQL中的某些模式不会在Postgres中使用,有些工作需要不同的思考。您可以使用数组RETURN NEXTRETURN QUERY语句:

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;