在 DO 块内使用由 psql 元命令设置的变量
Use variable set by psql meta-command inside of DO block
这是我想做的事情:
\set values foo,bar,baz
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(:'values', ',');
BEGIN
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
这会导致以下错误:
ERROR: syntax error at or near ":"
SELECT string_to_array(:'values', ',') INTO values...
^
这是我目前的解决方案,但感觉很老套:
\set values foo,bar,baz
PREPARE get_values AS SELECT string_to_array(:'values', ',');
DO $$
DECLARE
value TEXT;
values TEXT[];
BEGIN
EXECUTE 'EXECUTE get_values' INTO values;
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
回答
DO
需要一个带有 plpgsql 代码的 字符串文字 。 psql 中的字符串内不替换符号。
您可以将整个字符串连接到一个 psql 变量中,然后 然后 执行它。
漂亮的多行格式是不可能的,因为 (per documentation):
But in any case, the arguments of a meta-command cannot continue
beyond the end of the line.
简单示例:
test=# \set value foo
test=# \set do 'BEGIN\n RAISE NOTICE ''v: %'', ' :'value' ';\nEND'
test=# DO :'do';
NOTICE: v: foo
将换行符替换为 \n
(如果您不喜欢漂亮的格式,则将其删除)。基于此改编代码:
DO
'
DECLARE
_val text;
_vals text[] := string_to_array(>>values<<, '','');
BEGIN
FOREACH _val IN ARRAY _vals
LOOP
RAISE NOTICE ''v: %'', _val;
END LOOP;
END
'
看起来像这样:
test=# \set do 'DECLARE\n _val text;\n _vals text[] := string_to_array(' <b>:'values'</b> ', '','');\nBEGIN\n FOREACH _val IN ARRAY _vals\n LOOP\n RAISE NOTICE ''v: %'', _val;\n END LOOP;\nEND'
test=# DO :'do';
NOTICE: v: foo
NOTICE: v: bar
NOTICE: v: baz
DO
我为变量添加了 粗体 强调,以便更容易识别。
@Pavel 的相关回答 (ab)using a server session variable:
替代解决方案
准备好的语句
您当前的解决方案看起来还不错。我会简化:
PREPARE get_values AS SELECT * FROM regexp_split_to_table(:'values', ',');
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN EXECUTE
'EXECUTE get_values'
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
临时table
类似的临时解决方案table:
CREATE TEMP TABLE tmp AS SELECT * FROM regexp_split_to_table(:'values', ',') v;
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN
TABLE tmp
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
能够利用此解决方案:
- Passing argument to a psql procedural script
我在哪里设置变量并使用 current_setting()
检索它
\set values foo,bar,baz
SET vars.values TO :'values';
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(current_setting('vars.values'), ',');
BEGIN
FOREACH value IN ARRAY values LOOP
RAISE NOTICE 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql
这是我想做的事情:
\set values foo,bar,baz
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(:'values', ',');
BEGIN
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
这会导致以下错误:
ERROR: syntax error at or near ":" SELECT string_to_array(:'values', ',') INTO values... ^
这是我目前的解决方案,但感觉很老套:
\set values foo,bar,baz
PREPARE get_values AS SELECT string_to_array(:'values', ',');
DO $$
DECLARE
value TEXT;
values TEXT[];
BEGIN
EXECUTE 'EXECUTE get_values' INTO values;
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
回答
DO
需要一个带有 plpgsql 代码的 字符串文字 。 psql 中的字符串内不替换符号。
您可以将整个字符串连接到一个 psql 变量中,然后 然后 执行它。
漂亮的多行格式是不可能的,因为 (per documentation):
But in any case, the arguments of a meta-command cannot continue beyond the end of the line.
简单示例:
test=# \set value foo
test=# \set do 'BEGIN\n RAISE NOTICE ''v: %'', ' :'value' ';\nEND'
test=# DO :'do';
NOTICE: v: foo
将换行符替换为 \n
(如果您不喜欢漂亮的格式,则将其删除)。基于此改编代码:
DO
'
DECLARE
_val text;
_vals text[] := string_to_array(>>values<<, '','');
BEGIN
FOREACH _val IN ARRAY _vals
LOOP
RAISE NOTICE ''v: %'', _val;
END LOOP;
END
'
看起来像这样:
test=# \set do 'DECLARE\n _val text;\n _vals text[] := string_to_array(' <b>:'values'</b> ', '','');\nBEGIN\n FOREACH _val IN ARRAY _vals\n LOOP\n RAISE NOTICE ''v: %'', _val;\n END LOOP;\nEND'
test=# DO :'do';
NOTICE: v: foo
NOTICE: v: bar
NOTICE: v: baz
DO
我为变量添加了 粗体 强调,以便更容易识别。
@Pavel 的相关回答 (ab)using a server session variable:
替代解决方案
准备好的语句
您当前的解决方案看起来还不错。我会简化:
PREPARE get_values AS SELECT * FROM regexp_split_to_table(:'values', ',');
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN EXECUTE
'EXECUTE get_values'
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
临时table
类似的临时解决方案table:
CREATE TEMP TABLE tmp AS SELECT * FROM regexp_split_to_table(:'values', ',') v;
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN
TABLE tmp
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
能够利用此解决方案:
- Passing argument to a psql procedural script
我在哪里设置变量并使用 current_setting()
\set values foo,bar,baz
SET vars.values TO :'values';
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(current_setting('vars.values'), ',');
BEGIN
FOREACH value IN ARRAY values LOOP
RAISE NOTICE 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql