在 DO 块内使用 psql 元命令设置的变量

问题描述 投票:0回答:2

这就是我想做的:

\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...
                       ^

这是我目前的解决方案,但感觉很hacky:

\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;
postgresql session-variables dynamic-sql psql postgresql-9.4
2个回答
5
投票

回答

DO
需要带有 PL/pgSQL 代码的字符串文字(除非您声明不同的 PL)。 psql 中的字符串内部不会替换符号。
您可以将整个字符串连接到 psql 变量中,然后然后执行它。

相当多行的格式是不可能的,因为(每个文档):

但无论如何,元命令的参数不能继续 超出线路末端。

简单的例子:

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(' :'values' ', '','');\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)使用服务器会话变量的相关答案:

替代解决方案

准备好的声明

您当前的解决方案看起来并没有那么糟糕。我会简化:

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

临时表

使用临时表的类似解决方案:

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

4
投票

能够利用此解决方案:

我设置变量并使用

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
© www.soinside.com 2019 - 2024. All rights reserved.