[英]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.