循环遍历PL/pgSQL中给定的值列表

Guy*_*y s 6 arrays postgresql loops plpgsql

我正在尝试遍历几个字段并在它们上运行一个函数:

FOR field IN ARRAY['f1','f2'] LOOP
    execute pg_temp.converFieldToLower(newTableNameRaw,field)
END LOOP;
Run Code Online (Sandbox Code Playgroud)

这是我正在尝试使用的功能:

CREATE OR REPLACE FUNCTION pg_temp.converFieldToLower(t varchar, f varchar) RETURNS void AS $$
#variable_conflict use_variable
BEGIN
  EXECUTE concat_ws (' ', 'UPDATE',t,'SET',f,'= LOWER(',f,')');
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

看起来这不是声明数组的正确方法,我做错了什么?

ERROR:  syntax error at or near "ARRAY"
LINE 49:         FOR field IN ARRAY['f1','f2'] LOOP
Run Code Online (Sandbox Code Playgroud)

kli*_*lin 10

FOREACH循环是专门用于通过数组的值,例如的元素迭代设计:

FOREACH field IN ARRAY ARRAY['f1','f2'] LOOP
    execute pg_temp.converFieldToLower(newTableNameRaw,field) into res;
END LOOP;
Run Code Online (Sandbox Code Playgroud)

该功能是在Postgres 9.1中引入的.


Erw*_*ter 6

EXECUTE用于动态 SQL,循环中没有任何动态内容。
您可能打算使用PERFORM丢弃结果。看:

FOREACHfor循环,就像@klin已经提供的一样。看:

通常,纯 SQL 更简单、更快:

PERFORM pg_temp.converFieldToLower(newTableNameRaw, t.val)
FROM    unnest('{f1,f2}'::text[]) t(val);
Run Code Online (Sandbox Code Playgroud)

对于只有两个或三个常量或变量,只需将其拼写出来即可避免任何开销。更简单、更快。

PERFORM pg_temp.converFieldToLower(newTableNameRaw, 'f1');
PERFORM pg_temp.converFieldToLower(newTableNameRaw, 'f2');
Run Code Online (Sandbox Code Playgroud)

FOREACH对于每个数组元素进行更复杂的操作可能是一个好主意。

您添加的函数容易受到SQL 注入攻击。看:

这是一个安全的变体format()

CREATE OR REPLACE FUNCTION pg_temp.converFieldToLower(t text, f text)
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format(
'UPDATE %1$I
SET    %2$I =  lower(%2$I)
WHERE  %2$I <> lower(%2$I)', t, f);
END
$func$;
Run Code Online (Sandbox Code Playgroud)

在执行此操作时,我添加了一个WHERE子句来跳过不会更改行的更新操作 - 完全成本。