繁体   English   中英

如何在plpgsql中使用记录类型变量?

[英]How to use a record type variable in plpgsql?

如何将存储在记录类型变量中的查询结果用于同一存储的 function 中的另一个查询? 我使用 Postgres 9.4.4。

使用这样的表:

create table test (id int, tags text[]);
insert into test values (1,'{a,b,c}'),
                        (2,'{c,d,e}');

我写了一个 function(简体),如下所示:

CREATE OR REPLACE FUNCTION func(_tbl regclass)
RETURNS TABLE (t TEXT[], e TEXT[])
LANGUAGE plpgsql AS $$
DECLARE
  t RECORD;
  c INT;
BEGIN
  EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t;
  SELECT count(*) FROM t INTO c;
  RAISE NOTICE '% results', c;
  SELECT * FROM t;
END
$$;

...但没有用:

select func('test');
 ERROR: 42P01: relation "t" does not exist LINE 1: SELECT count(*) FROM t ^ QUERY: SELECT count(*) FROM t CONTEXT: PL/pgSQL function func(regclass) line 7 at SQL statement LOCATION: parserOpenTable, parse_relation.c:986

核心误解: record变量包含单行 (或为NULL),而不是表(0-n行的已知类型)。 Postgres或PL / pgSQL没有“表变量” 根据任务的不同,有各种替代方案:

因此,您不能将行分配给record类型变量。 在这个声明中:

EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t;

... Postgres 分配第一行并丢弃其余部分。 由于“第一个”在您的查询中没有很好地定义,因此您最终会选择一个任意选择。 显然是由于一开始就提到的误解。

record变量也不能用于代替SQL查询中的表。 这是导致错误的主要原因:

关系“t”不存在

现在应该很清楚, count(*)开头没有任何意义,因为t只是一个记录/行 - 除此之外不可能。

最后(即使其余的工作),你的返回类型似乎是错误的: (t TEXT[], e TEXT[]) 因为你选择id, tagst ,你想要返回类似(id int, e TEXT[])

你想要做的是这样的

CREATE OR REPLACE FUNCTION func(_tbl regclass)
  RETURNS TABLE (id int, e text[]) AS
$func$
DECLARE
   _ct int;
BEGIN
   EXECUTE format(
      'CREATE TEMP TABLE tmp ON COMMIT DROP AS
       SELECT id, tags FROM %s'
    , _tbl);

   GET DIAGNOSTICS _ct = ROW_COUNT; -- cheaper than another count(*)

   -- ANALYZE tmp;  -- if you are going to run multiple queries

   RAISE NOTICE '% results', _ct;

   RETURN QUERY TABLE tmp;
END
$func$ LANGUAGE plpgsql;

调用(注意语法!)

SELECT * FROM func('test');

有关:

只是一个概念证明。 在选择整个表时,您只需使用基础表。 实际上,你在查询中会有一些WHERE子句......

注意潜伏类型不匹配, count()返回bigint ,你不能将它分配给integer变量。 需要一个强制转换: count(*)::int

但是我完全取代了它,在EXECUTE之后运行它会更便宜:

GET DIAGNOSTICS _ct = ROW_COUNT; 

手册中的详细信息。

为何ANALYZE


另外:普通SQL中的CTE通常可以完成这项工作:

以下是我在 redshift 数据库的 plpgsql 中使用 RECORD 类型变量的几种方法

  1. 运行一个循环
  2. 存储记录变量

代码类型 1

    SOME BOILERPLATE

    $body$
    declare 
    
    arow record ;
    
    begin 
    for arow in ({table})    -- use of record type
      loop
      update #some_table 
        
       column1_some_table := arow.column1,
       column2_some_table := arow.column2 
       where some_condition
      
      end loop ; 
   end ;
   $body$;
  

代码类型 2

    SOME BOILERPLATE

    $body$
    declare 
    
    arow record ;
    
    begin 
    while (counter <= max_counter)
    loop
    select column1, column2 into arow   -- use of record type
      from {table}
      update #some_table 
        
       column1_some_table := arow.column1,
       column2_some_table := arow.column2 
       where some_condition
      counter = counter+1
      end loop ; 
   end ;
   $body$;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM