[英]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, tags
到t
,你想要返回类似(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
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.