Postgresql 如何使用plpgsql函数插入数据?

Postgresql 如何使用plpgsql函数插入数据?,postgresql,Postgresql,我试图使用plpgsql函数或存储过程将数据插入表中。但是,我想一次插入多条记录。现在这些都是VARCHAR,所以我想我可以使用类似函数的函数(tablename VARCHAR,records VARCHAR[]])。但后来我发现plpgsql中对多维数组的支持并没有那么好 这就是我的函数目前的样子。这不会产生我想要的结果。 当我问 SELECT insert_data('tennis', ARRAY[ARRAY['1','2'], ARRAY['3','4']]) 我得到以下错误 ERRO

我试图使用plpgsql函数或存储过程将数据插入表中。但是,我想一次插入多条记录。现在这些都是VARCHAR,所以我想我可以使用类似
函数的函数(tablename VARCHAR,records VARCHAR[]])
。但后来我发现plpgsql中对多维数组的支持并没有那么好

这就是我的函数目前的样子。这不会产生我想要的结果。 当我问

SELECT insert_data('tennis', ARRAY[ARRAY['1','2'], ARRAY['3','4']])
我得到以下错误

ERROR:  syntax error at or near "{"
LINE 1: INSERT INTO tennis VALUES (null, {{1}}), (null, {{3}});
                                         ^
QUERY:  INSERT INTO tennis VALUES (null, {{1}}), (null, {{3}});
CONTEXT:  PL/pgSQL function "insert_data" line 26 at EXECUTE statement
然而,我期待像这样的查询

INSERT INTO tennis VALUES (null, '1', '2'), (null, '3', '4');
这是可行的,因为乒乓球有这样的结构

CREATE OR REPLACE FUNCTION insert_data (dsetname_in VARCHAR, records VARCHAR[][])
RETURNS BOOLEAN AS $PROC$
DECLARE
    insertquery TEXT;
    val VARCHAR;
    i INT;
    j INT;
BEGIN
    insertquery = $$INSERT INTO $$ || dsetname_in || $$ VALUES $$;
    FOR i IN array_lower(records, 1)..array_upper(records, 1)
    LOOP
        insertquery = insertquery || $$(null, $$;
        FOR j IN array_lower(records[i:i], 1)..array_upper(records[i:i], 1)
        LOOP
            val = records[i:i][j:j];
            insertquery = insertquery || val;
            IF j <> array_upper(records[i:i], 1) THEN
                insertquery = insertquery || $$, $$;
            END IF;
        END LOOP;
        insertquery = insertquery || $$)$$;
        IF i <> array_upper(records, 1) THEN
            insertquery = insertquery || $$, $$;
        END IF;
    END LOOP;
    insertquery = insertquery || $$;$$;
    EXECUTE insertquery;
    RETURN TRUE;
END;$PROC$ LANGUAGE 'plpgsql';
创建或替换函数insert_数据(VARCHAR中的dsetname_,记录VARCHAR[])
以$PROC形式返回布尔值$
声明
插入查询文本;
瓦尔·瓦尔查尔;
i INT;
j INT;
开始
insertquery=$$INSERT INTO$$| | |$$VALUES$$中的$$dsetname_;
对于数组中较低的i(记录,1)…数组中较高的i(记录,1)
环
insertquery=insertquery | |$$(null,$$);
对于数组中较低的j(记录[i:i],1)…数组中较高的j(记录[i:i],1)
环
val=记录[i:i][j:j];
insertquery=insertquery | | val;
如果j数组_上位(记录[i:i],1),则
insertquery=insertquery | |$$,$$;
如果结束;
端环;
insertquery=insertquery | |$$)$$;
如果我数组_upper(记录,1),那么
insertquery=insertquery | |$$,$$;
如果结束;
端环;
insertquery=insertquery | |$$;$$;
执行insertquery;
返回TRUE;
结束$PROC$语言“plpgsql”;

我怀疑整个方法的价值,因为我看不出它增加了任何有用的抽象层次;但如果必须这样做,并且所有值都是字符串,我认为最干净的方法是:

CREATE OR REPLACE FUNCTION insert_data(dsetname_in text, records text[])
RETURNS VOID LANGUAGE plpgsql AS $PROC$
DECLARE
  insertquery text;
  i int;
BEGIN
  insertquery := 'INSERT INTO ' || dsetname_in || ' VALUES ';
  FOR i IN array_lower(records, 1)..array_upper(records, 1)
  LOOP
    insertquery := insertquery || '(null, ' || records[i] || '),';
  END LOOP;
  insertquery := left(insertquery, char_length(insertquery) - 1);
  EXECUTE insertquery;
END;
$PROC$;
然后,您可以这样调用它,这似乎比您为嵌套数组显示的更干净:

SELECT insert_data('tennis',
                   ARRAY[$$'1','2'$$,
                         $$'3','4'$$]);

我将不从数据库而是从外部代码执行此操作。这并不能解释为什么外部代码生成此字符串更容易:
选择insert_data('netsing',ARRAY[ARRAY['1','2',ARRAY['3','4']])
而不是这个:
插入网球值(null,'1','2'),(null,'3','4')
。不理解为什么第一个是您想要的,这使得很难对建议进行推理。我希望在我的外部代码中使查询尽可能抽象。因此,与其调用我自己的函数,不如调用INSERT语句。是的,这看起来更好。谢谢你和我一起思考,也许这不是正确的方式,但是你今天确实让我很开心。我只是想把“大”查询留给数据库,希望代码更干净。我将在游戏结束时看到它的作用。在处理数据中的引号时要小心,尤其是SQL注入。通过这种方式,很多处理类似事情的常用基础设施都不容易实现。我还没有确切地分析这里存在的风险,但它确实“感觉”到您需要在这方面谨慎行事。我使用的是java.sql.CallableStatement。这会降低SQL注入的风险吗?是否,记录数组中有文本?是的,数组中每个字符串中的字符串嵌套可能会使正常保护无法触及。当心小桌子。