重复使用占位符(“?”)在DBI prepare中的作用

8

有没有一种方法可以重复使用在DBI准备语句中使用的问号?考虑以下代码:


$sth=$dbh->prepare("INSERT INTO mytable(a,b,c) SELECT ?,B(?),C(?)");
$sth->execute($a,$a,$a);

最好使用类似这样的东西:


#I'm making this up as something I hope exists
$sth=$dbh->prepare("INSERT INTO mytable(a,b,c) SELECT ?,B(?:1),C(?:1)");
$sth->execute($a);

请注意,在执行中只传递了一个 $a 而不是三个。在实际生活中是否有方法可以做到这一点?


3
请不要将$a(和$b)作为随机变量使用。它们是特殊的并且有专门的定义:http://perldoc.perl.org/perlvar.html#%24a - pilcrow
4个回答

7

这取决于你所使用的DBD。例如,使用带有$1占位符样式的DBD::Pg,或者使用命名占位符和bind_param的DBD::Oracle,您可以完全按照自己的意愿进行操作。但是,如果使用适用于DBI的通用?占位符样式,则不可能实现。


4
如果您使用库来为您生成SQL语句,例如SQL::Abstract或全面的ORM(如DBIx::Class),您就不必担心这些问题。
或者,您可以只用几行代码做类似的事情:
my $sql = 'INSERT INTO ...blah blah... VALUES (' . (join(', ', ('?') x scalar(@insert_elements))) . ')';

1
所有这些解决方案都需要三次输入“$a”,而我相信这是User1试图避免的唯一任务。 - Richard Simões
@Bipedal:可以将绑定参数传递为 (($a) x 3) - Ether
是的,x 运算符可以用作解决方法,但这并不改变以下两点:1)OP 问是否有一种方法可以传递一个变量,并将其绑定到多个占位符;2)使用 x 运算符会为每个占位符传递多次变量,这正是问题想要避免的。 - Dave Sherohman
@Dave:其实没有什么好的理由要避免它。如果查询中有三个绑定参数,那么应该传入三个参数。也许我不太理解这种特定类型的查询,但是OP想要的似乎很奇怪。 - Ether
@Ether:我知道这是一个非常老的问题,但这并不奇怪;特别是当你使用数组时。你可能有像select ($1)[i] from generate_series(1,array_upper($1,1) ) i这样的东西,它从一个数组创建了一个表。数组越大,查询往返所需的时间就越长。如果您发送相同的参数两次,它将进一步增加网络传输时间。最小化通过线路发送的数据量应该提高全面的效率和安全性。 - vol7ron

3

@hobbs' 答案 是正确的 -- 默认的DBI占位符无法解决这个问题。@Ether的 答案 是正确的 -- 一个SQL抽象可以使这成为一个非问题。

然而,通常只需要绑定每个不同的参数化值一次。在你的例子中,使用一个标量派生表将用户提供的值 按名称 提供给查询的其余部分:

my $sth = $dbh->prepare(<<'__eosql');
    INSERT INTO mytable(a,b,c)
                SELECT x, B(x), C(x) FROM (SELECT ? AS x) subq
                              -- Subquery may vary from DB to DB:
                              --    "FROM (SELECT ? AS x FROM DUAL) subq"
                              --    "FROM (SELECT ? FROM rdb$database) subq(x)"
                              --    "FROM (VALUES (?)) subq(x)"
                              -- etc.
__eosql

for $v (@values) {
    $sth->execute($v);
}

通常情况下,这比另一种方式更加高效,因为用户提供的参数通常只需传输一次,而不是N次。

2

您可以在一个SQL语句中设置SQL变量,然后在下一个查询中多次使用该变量。

$dbh->do('set @reusable = ?', undef, $perl_var);
$dbh->select_arrayref('select * from table where cola = @reusable or colb = @reusable');

没有重复的变量,同时你仍然能够获得参数化查询的安全性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接