简体   繁体   English

perl / dbi / sql被“操作必须使用可更新的查询”困扰

[英]perl/dbi/sql stumped by “operation must use an updatable query” error

I've a Perl script that builds up an sql cmd to set certain fields to NULL in a certain table in an MS Access db ( sorry). 我有一个Perl脚本,该脚本建立了一个sql cmd来将MS Access数据库中某些表中的某些字段设置为NULL(对不起)。 Here's a simplified mockup. 这是一个简化的模型。

my $nonKeyFields_hashref = { "country" => "ZZZ",
                             "address3" => "FOO"
                           };
my $keyFields_hashref = { "address1" => "1212 O'Mally Street",    # embedded single quote here is causing the problem
                          "client ID" => "1234567"
                        };
my $sqlCmd = "UPDATE myTable SET ";
$sqlCmd .= join( ", " , map{ "[?} = NULL "} keys $nonKeyFields_hashref;
$sqlCmd .= " WHERE ";
$sqlCmd .= join( " AND " , map{ "[?} = ? "} keys $keyFields_hashref;

# sqlCmd contains "UPDATE myTable SET [?] = NULL, [?} = NULL WHERE [?] = ? AND [?] = ?"

$sth = $dbh->prepare( $sqlCmd);
if( !defined( $sth)) {
  _pushErrorMsg("sth failed to define - ".$DBI::errstr);
  $errorHit = 1;
} else {
  my @cmd_arry = ();
  push( @cmd_arry, $_ ) for keys $nonKeyFields_hashref;
  push( @cmd_arry, $_ , $keyFields_hashref->{$_} ) for keys $keyFields_hashref;
  print Dumper( @cmd_arry);

  # dumper shows @cmd_arry contains ("country", "address3", "address1", "1212 O'Mally Street", "client ID", "1234567")
  # which is six elements, which jibes with the query's question-marks

  $sth->execute( @cmd_arry);    # errors here with the given message
  ....
}

this code works great when the data does NOT contain nasty embedded single-quotes. 当数据不包含讨厌的嵌入式单引号时,此代码非常有用。 I'd hoped the binding would solve this problem but no such luck. 我希望绑定可以解决这个问题,但是没有运气。

Anyone have a solution to this single-quote issue? 有人对这个单引号问题有解决方案吗?

Thanks in advance, 提前致谢,

Still-learning Steve. 仍在学习的史蒂夫。

That code contains syntax errors due to a) missing closing ) on the join calls b) missing use for Data::Dumper. 该代码包含语法错误,原因是a)缺少联接调用的close)b)缺少对Data :: Dumper的使用。 I'm assuming you are using a recent Perl since you seem to be expecting $hash_references are automatically dereferenced. 我假设您正在使用最新的Perl,因为您似乎期望$ hash_references被自动取消引用。

It is unusual for a database engine to accept parameters for column names - this definitely would not work with most databases. 数据库引擎接受列名参数是不寻常的-这绝对不适用于大多数数据库。

The single quote you are talking about has no impact on this script as far as I can see - it is just broken wrt the code in the else pushing too many paramaters for the SQL statement. 就我所知,您在谈论的单引号对该脚本没有影响-它只是破坏了代码,而其他代码又为SQL语句增加了太多参数。 The SQL statement wants 4 column names and you push 4 column names and 2 values. SQL语句需要4个列名,然后推4个列名和2个值。

I presume you meant " push( @cmd_arry, $_ , $keyFields_hashref->{$_}" to be "push( @cmd_arry, $_". 我假设您是说“ push(@cmd_arry,$ _,$ keyFields_hashref-> {$ _}”)是“ push(@cmd_arry,$ _”。

Some slight refactoring did the trick: 一些轻微的重构就达到了目的:

$sqlCmd = "UPDATE [$tableName] SET ";
$sqlCmd .= join( ", ", map { "[$_] = NULL "} keys $nonKeyFields_hashref);
$sqlCmd .= " WHERE ";
$sqlCmd .= join( " AND ", map { "[$_] = ? "} keys $keyFields_hashref);
# sneaky values may contain embedded single-quotes for GoGo's , 4343 Little's Court, etc

my $sth = undef;
$sth = $dbh->prepare( $sqlCmd);
if( !defined( $sth)) {
  _pushErrorMsg("sth failed to define - ".$DBI::errstr);
  $errorHit = 1;
} else {
  my @cmd_arry = ();
  push( @cmd_arry, $keyFields_hashref->{$_} )  for keys( $keyFields_hashref);
  print Dumper( @cmd_arry);
  my $resultCnt = $sth->execute( @cmd_arry);
  if( my $errorMsg = $dbh->errstr ) 
 ....

Thanks to all who responded! 感谢所有回应!

Still-learning Steve 仍在学习的史蒂夫

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM