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

l5tcr1uw  于 2023-01-25  发布在  PostgreSQL
关注(0)|答案(2)|浏览(226)

我如何使用存储在一个记录类型变量中的查询结果,在同一个存储函数中进行另一个查询?我使用Postgres 9.4.4。
有这样一张table:

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

我写了一个函数(简化)如下:

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
$$;

......但不起作用:
一个二个一个一个

ccrfmcuu

ccrfmcuu1#

核心误区:一个record变量只保存一行(或者为NULL),而不是一个表(0-n行,类型已知)。Postgres或PL/pgSQL中没有"表变量"。根据任务的不同,有多种选择:

  • PostgreSQL表格变量
  • 将多个行和列选择到记录变量中

因此,不能将***多个***行赋给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');

相关:

  • Postgres从动态sql字符串创建本地临时表(在提交删除时)

这只是一个概念证明。当您选择整个表时,您只需使用底层表。实际上,您将在查询中使用一些WHERE子句...
注意潜在的类型不匹配,count()返回bigint,你不能把它赋给integer变量。count(*)::int.
但是我完全替换了它,在EXECUTE之后运行它更便宜:

GET DIAGNOSTICS _ct = ROW_COUNT;

手册中的详细信息。
为什么是ANALYZE

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

  • 从plpgsql中的FOR循环切换到基于集合的SQL命令
u2nhd7ah

u2nhd7ah2#

以下是我在红移数据库中使用plpgsql中RECORD类型变量的几种方法
1.运行循环
1.存储记录变量
代码类型1

$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

$body$
    declare 
    
    arow record ;
    counter int := 0;
    max_counter int := 0;
    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$;

相关问题