plpgsql动态插入以表名作为变量和where子句中的数组变量

plpgsql dynamic insert with tablename as variable and array variable in where clause

我正在尝试编写一个运行插入语句的函数,该语句以 table 名称作为变量,where 子句接受一个数组作为另一个变量。

CREATE OR REPLACE FUNCTION f_dynamic_sql()
  RETURNS void
  LANGUAGE plpgsql
AS
$body$

DECLARE 
rec record;
iterator float4 := 1;
tbl_name text;

BEGIN
DROP TABLE IF EXISTS t_ar; CREATE TEMP TABLE t_ar (reg text, zones text[]);
INSERT INTO t_ar VALUES 
('NA', '{"US","UG","UC","UR"}'),
('NE', '{"UK", "SP"}'),
('LA', '{"CA","EC","WC","EC","WC"}');

FOR rec IN SELECT zones from t_ar
    LOOP 
  tbl_name := 'schema.table_' || iterator; 
  EXECUTE format('INSERT INTO %s 
          SELECT
            DATE_PART(''MONTH'', month)::INT AS month,
            SUM(COALESCE(prev_year,0))::INT AS py,
            SUM(COALESCE(last_year,0))::INT AS ly
        FROM org_table
        WHERE load_area IN (SELECT UNNEST(rec.zones))
        GROUP BY 1
        ORDER BY 1', tbl_name); 

    iterator := iterator + 1;
END LOOP;
END;
$body$
  VOLATILE
  COST 100;

这在执行格式之外运行良好,但后来我无法将 table 名称作为变量,但在执行格式内它显示 SQL 查询中的语法错误。 SQL 查询在外面运行正常。

您需要在 format() 函数中使用占位符和参数。

使用 EXECUTE format() 时的一个实用技巧 - 使用 RAISE NOTICE '%', 而不是 EXECUTE 和 运行 psql 中的函数来查看它实际生成的查询。当您确定生成的查询正确时,将 RAISE NOTICE '%', 替换为 EXECUTE。示例:

...
FOR rec IN SELECT reg, zones FROM t_ar
LOOP 
RAISE NOTICE '%', format('
    INSERT INTO my_schema.table_%s 
    SELECT
        DATE_PART(''MONTH'', month)::INT AS month,
        SUM(COALESCE(prev_year,0))::INT AS py,
        SUM(COALESCE(last_year,0))::INT AS ly
    FROM org_table
    WHERE load_area = ANY (%L)
    GROUP BY 1
    ORDER BY 1', rec.reg, rec.zones); 
END LOOP;
...