Postgresql 如何使用plpgsql函数插入数据?
我试图使用plpgsql函数或存储过程将数据插入表中。但是,我想一次插入多条记录。现在这些都是VARCHAR,所以我想我可以使用类似Postgresql 如何使用plpgsql函数插入数据?,postgresql,Postgresql,我试图使用plpgsql函数或存储过程将数据插入表中。但是,我想一次插入多条记录。现在这些都是VARCHAR,所以我想我可以使用类似函数的函数(tablename VARCHAR,records VARCHAR[]])。但后来我发现plpgsql中对多维数组的支持并没有那么好 这就是我的函数目前的样子。这不会产生我想要的结果。 当我问 SELECT insert_data('tennis', ARRAY[ARRAY['1','2'], ARRAY['3','4']]) 我得到以下错误 ERRO
函数的函数(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注入的风险吗?是否,记录数组中有文本?是的,数组中每个字符串中的字符串嵌套可能会使正常保护无法触及。当心小桌子。