准备好的陈述:使用未命名和未编号的问号样式位置占位符

时间:2015-06-22 09:27:21

标签: postgresql

在Postgres以外的SQL系统中,例如MySQL,预准备语句可以使用问号?作为预备语句中数据的占位符。

INSERT INTO foo (id, name) VALUES (?, ?), (?, ?);

但是,在Postgres中,唯一可用的占位符似乎是编号占位符,因此Postgres的上述INSERT语句如下所示:

INSERT INTO foo (id, name) VALUES ($1, $2), ($3, $4);

使用此语法,就会出现问题,当我尝试插入大量的行的在一个语句,一个万行和10列,我必须有占位符范围从$1 to $100,000,这导致3-查询大小增加4倍。

对于准备好的声明,Postgres是否支持任何类型的未编号和未命名的占位符?

编辑:

我正在使用预准备语句,因为它们允许防御SQL注入。所以我的目标是尽可能快地保持我的批量插入,同时保持插入过程的安全。

1 个答案:

答案 0 :(得分:2)

Prepared语句用于加速使用不同参数重复执行同一查询。 如果您的目标是一次插入多行,则最好执行常规插入查询,这将比准备好的插入更快。但是,如果您坚持使用此解决方案,则可以使用数组作为预准备语句的参数。例如:

create table foo(id int, val text);

prepare insert_into_foo (int[], text[]) as 
    insert into foo 
    select unnest(a), unnest(b)
    from (values ($1, $2)) v(a, b);

execute insert_into_foo (array[1,2,3], array['a','b','c']);
execute insert_into_foo (array[4,5,6,7], array['d','e','f','g']);

deallocate insert_into_foo; 

这个技巧的主要缺点是你需要非常小心地在数组中放入相同数量的参数。任何错误都可能是痛苦的。因此,我建议将它与保险丝一起使用:

prepare insert_into_foo (int[], text[]) as 
    insert into foo 
    select unnest(a), unnest(b)
    from (values ($1, $2)) v(a, b)
    where array_length(a, 1) = array_length(b, 1); -- fuse

execute insert_into_foo (array[1,2], array['a','b','c']); -- does nothing