【问题标题】:Can't find cause of HY093 Invalid parameter number: number of bound variables does not match num ber of tokensCan't find cause of HY093 Invalid parameter number: number of bound variables does not match number of tokens
【发布时间】:2017-02-28 14:39:29
【问题描述】:

我有一个页面,上面有 8 个复选框。根据选中的复选框数量,创建一条 sql 语句。例如:如果选中了两个复选框,则必须更新一个包含 24 个名称的数组(最多 32 个名称)。勾选 3 时,需要更新 20 行。

在我的 PHP 逻辑中,我检查选中了多少个复选框,假设选中了 3 个。然后我使用占位符创建 PDO 更新语句,如下所示:

.
.
case 20:
  $sstring = "left1 = :n1, left2 = :n2, left3 = :n3, left4 = :n4,
              left5 = :n5, left6 = :n6, left7 = :n7, left8 = :n8,
              left9 = :n9, left10 = :n10, left11 = :n11, left12 = :n12,
              left13 = :n13, left14 = :n14, left15 = :n15, left16 = :n16,
              left17 = :n17, left18 = :n18, left19 = :n19, left20 = :n20";
  break;
.
.

然后,我创建 sql 语句,如下所示(记住:PHP):

$sql = "UPDATE drawleft SET " . $sstring . " WHERE year = :year";

接下来,我做准备:

$stmt1=$db->prepare($sql);

最后,我完成了发送数据的更新:

.
.
case 20:
  $qstring = "':year' => $year, ':n1' => $nm_array[0], ':n2' => $nm_array[1],
              ':n3' => $nm_array[2], ':n4' => $nm_array[3], ':n5' => $nm_array[4],
              ':n6' => $nm_array[5], ':n7' => $nm_array[6], ':n8' => $nm_array[7],
              ':n9' => $nm_array[8], ':n10' => $nm_array[9], ':n11' => $nm_array[10],
              ':n12' => $nm_array[11], ':n13' => $nm_array[12], ':n14' => $nm_array[13],
              ':n15' => $nm_array[14], ':n16' => $nm_array[15], ':n17' => $nm_array[16],
              ':n18' => $nm_array[17], ':n19' => $nm_array[18], ':n20' => $nm_array[19]";
break;
.
.

现在当我执行$result = $stmt1->execute(array($qstring)); 时,我得到一个错误 500,我在 apache error_log 中看到 HY093 错误:Invalid parameter number: number of bound variables does not match number of tokens

当我执行以下操作时(没有array):

$result = $stmt1->execute($qstring);

我收到 PDO 警告:PDOStatement::execute() expects parameter 1 to be array, string given

比较占位符的数量和execute()期间提交的值的数量,我只能得出结论,它们是相同的。

那么,请谁能告诉我我在这里做错了什么? (除了编码不太好……)

谢谢。

【问题讨论】:

    标签: php mysql arrays pdo


    【解决方案1】:
    $qstring = "':year' => $year, ':n1' => $nm_array[0], ':n2' => $nm_array[1],
                  ':n3' => $nm_array[2], ':n4' => $nm_array[3], ':n5' => $nm_array[4],
                  ':n6' => $nm_array[5], ':n7' => $nm_array[6], ':n8' => $nm_array[7],
                  ':n9' => $nm_array[8], ':n10' => $nm_array[9], ':n11' => $nm_array[10],
                  ':n12' => $nm_array[11], ':n13' => $nm_array[12], ':n14' => $nm_array[13],
                  ':n15' => $nm_array[14], ':n16' => $nm_array[15], ':n17' => $nm_array[16],
                  ':n18' => $nm_array[17], ':n19' => $nm_array[18], ':n20' => $nm_array[19]";
    

    需要

    $qstring = array(':year' => $year, ':n1' => $nm_array[0], ':n2' => $nm_array[1],
                  ':n3' => $nm_array[2], ':n4' => $nm_array[3], ':n5' => $nm_array[4],
                  ':n6' => $nm_array[5], ':n7' => $nm_array[6], ':n8' => $nm_array[7],
                  ':n9' => $nm_array[8], ':n10' => $nm_array[9], ':n11' => $nm_array[10],
                  ':n12' => $nm_array[11], ':n13' => $nm_array[12], ':n14' => $nm_array[13],
                  ':n15' => $nm_array[14], ':n16' => $nm_array[15], ':n17' => $nm_array[16],
                  ':n18' => $nm_array[17], ':n19' => $nm_array[18], ':n20' => $nm_array[19]);
    

    【讨论】:

    • 谢谢!就是这样。一直在学习!
    【解决方案2】:

    我无法做出任何合理的解释,为什么您在此处使用命名占位符。

    使用位置占位符,您根本不需要这样的怪物阵列。可能还有一个怪物开关盒。

    鉴于你的 $sstring 就像

    foo=?, bar=?, baz=? ...
    

    你可以做一些简单的事情

    $stmt = $pdo->prepare("UPDATE drawleft SET $sstring WHERE year = ?");
    $nm_array[] = $year;
    $stmt->execute($nm_array);
    

    这个。是。全部。

    只需确保 $sstring 中的字段名称不是 vulnerable to SQL injection

    【讨论】:

      【解决方案3】:

      尝试更易读的版本:

      代替:

      $sql = "UPDATE drawleft SET " . $sstring . " WHERE year = :year";
      

      使用:

      $sql = "UPDATE drawleft SET left=:n1, left2=:n2 WHERE year = :year";
      $prepared = $stmt1->prepare($sql);
      $result = $prepared->execute(array(':n1' => $nm_array[0], ':n2' => $nm_array[1], ':year' => $your_year));
      

      另一种方式:

      $stmt = $dbh->prepare("UPDATE drawleft SET left=:n1, left2=:n2 WHERE year = :year");
      $stmt->bindParam(':n1', $nm_array[0]);
      $stmt->bindParam(':n2', $nm_array[1]);
      $stmt->bindParam(':year', $your_year);
      $result = $prepared->execute();
      

      【讨论】:

      • Dan,我同意这更具可读性,但由于将更新的字段数量取决于选中的复选框数量,因此我需要构造 $sql 的 SET 部分,如以及执行(数组(相应的部分。谢谢。
      • @notaverygoodprogrammer 好的,我明白了,也许是时候为未来转向正确的方法了,ORM。我个人使用 Doctrine 有很多选择,但也有很多。您可以先使用 DBAL 而不是整个 ORM。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-05
      • 1970-01-01
      • 2017-03-25
      • 2013-03-19
      • 2018-04-22
      相关资源
      最近更新 更多