1

我根据某些条件(例如操作类型或某个值的存在)通过向INSERT语句添加字段来构建查询。但是随后我必须为execute具有不同参数列表的不同 DBI 分支,如下所示:

if ($x) {$extraFields .= ' , X'; $extraValues= ',? '}
if ($y) {$extraFields .= ' , Y, Z'; $extraValues= ',?, ? '}

my $theBasicQuery = "INSERT INTO sometable (A, B, $extraFields) VALUES (?, ? $extraValues)";

$sth = $dbh->prepare($theBasicQuery) or error

# but I dont want to have to do this if for execute
if ($x) {$sth->execute(1,2,99);}
if ($y) {$sth->execute(1,2,88, 77);}

我宁愿做这样的事情:

{$sth->execute($anArrayWithDifferentParams);}

这可能吗?还是有另一种方法可以做类似的事情?

4

4 回答 4

6

为了更直接地回答这个问题,使用数组而不是标量列表执行查询的方法只是将数组传递给它。 $sth->execute(@params)会工作得很好。

if ($x) {$extraFields .= ' , X'; $extraValues = ',? '; @params = (99); }
if ($y) {$extraFields .= ' , Y, Z'; $extraValues = ',?, ? '; @params = (88, 77); }

my $theBasicQuery = "INSERT INTO sometable (A, B, $extraFields) VALUES (?, ? $extraValues)";

$sth = $dbh->prepare($theBasicQuery) or error

$sth->execute(1,2, @params);
于 2013-02-27T21:32:40.730 回答
4

我强烈建议使用 SQL 构建工具来帮助您解决此问题。我最喜欢的是SQL::Interp,与DBIx::Simple结合使用。这样的工具将为您管理绑定变量,并且 DBIx::Simple 还自动为您处理准备和重用语句句柄。使用 DBIx::Simple/SQL::Interp 的解决方案如下所示:

$db->iquery("INSERT INTO sometable", {
    a => 1,
    b => 2,
    %extra
});

SQL::Abstract 也很流行,并且有一个语法相似的解决方案。

于 2013-02-27T20:58:01.723 回答
2

一种方法:

my %insert = ( A => 1, B=> 2 );

if ($condition_x) {
  $insert{X} = 99;
}

if ($condition_y) {
  $insert{Y} = 88;
  $insert{Z} = 77;
}

# 1. sprintf isn't very perlish, but I find it clearer here
# 2. quote_identifier():  you won't ever need this until you need it very badly
#
my $query = sprintf('INSERT INTO tbl (%s) VALUES (%s)',
                       join ', ' => map { $dbh->quote_identifier($_) } keys %insert,
                       join ', ' => ('?') x keys %insert);

my $sth = $dbh->prepare($query);  # Perhaps prepare_cached, instead?
$sth->execute(values %insert);

警告:!DIY

如果可能的话,不要自己做!按照其他地方的建议使用模块。其他人已经解决了这个问题,比上面的更令人信服和可靠。

于 2013-02-27T21:27:15.970 回答
0

您可能会发现我的DBIx::PreQL库对此类任务很有帮助。它提供了一种标记 SQL 查询以根据可用数据进行处理的方法。

DBIx::PreQL 使用简单的前缀和命名占位符来标记应该包含哪些查询行。

例如,*表示“始终包含”和&表示“如果该行的所有数据字段都存在,则包含”。

您的查询将被标记如下:

*  INSERT INTO sometable (
*     A
*    ,B
&    ,C !C!  
&    ,D  !D!
)
*VALUES (
*   ?A?
*  ,?B?
&  ,?C?
&  ,?D?
* )

然后您将查询和数据哈希传递{ A => '123', B => 'foo', D => 'bar' }给查询处理器,它将返回查询:

INSERT INTO sometable (
     A
    ,B
    ,D
)
VALUES (
   ?
  ,?
  ,?
 )

和参数列表(123, 'foo', 'bar')

于 2013-02-27T23:46:13.547 回答