【问题标题】:PDOStatement->prepare and PDOStatement->bindParam() combination not working [duplicate]PDOStatement->prepare 和 PDOStatement->bindParam() 组合不起作用[重复]
【发布时间】:2014-09-11 05:58:10
【问题描述】:

我有一些代码应该循环遍历值并更改表中的条目。变量 $change_val、$column 和 $id 的 5 个值都正确回显,所以我认为我对 bindParam 的使用有问题(但我不确定它是什么)。

$connection = new PDO("mysql:host=localhost;dbname=logbook", $username, $password);
$perform_edit = $connection->prepare("UPDATE contacts SET :column = :value WHERE name_id = :name_id");

[Definition of Arrays]

for ($i = 1; $i <= 5; $i++) {

    if (!empty($_POST[ $change_array[$i]])) {
        $change_val = $_POST[$change_array[$i]];
        $column = $column_array[$i];
        $id = $_POST["name_id_ref"];
        $perform_edit->bindParam(":column", $column, PDO::PARAM_STR);
        $perform_edit->bindParam(":value", $_POST[$change_array[$i]], PDO::PARAM_STR);
        $perform_edit->bindParam(":name_id", $_POST["name_id_ref"], PDO::PARAM_INT);
        $perform_edit->execute();
        }
}

$_POST 语句在那里是因为我想要的值实际上是从另一个文件传递的。但是,当我在循环中放置适当的 echo 语句时,它们都会打印出正确的值。

我也尝试过 bindValue,但也没有用。我没有看到任何错误,而且至少可以顺利编译——只是不像它们应该的那样。表中没有任何变化。

这里有什么问题?

【问题讨论】:

  • column 一方面是保留字 dev.mysql.com/doc/refman/5.5/en/reserved-words.html - 然而,你不能这样做 SET :column 所以你'您需要为其设置一个变量,或者选择实际的列名。
  • 连接打开后立即添加$connection-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);。你站在让错误弹出。
  • @Fred-ii- 啊!优秀。在我所有的连接之后,我将开始放置它。问题是有五列将被编辑,并且这些列在整个循环中都会发生变化。我可以将prepare语句放在循环中,但这不是效率低下吗?
  • TBH,当我不得不做你想做的事情时,我很喜欢循环。您可以尝试一下,看看性能如何;值得一试。
  • 查看这些问答的stackoverflow.com/q/20531613stackoverflow.com/q/12043967stackoverflow.com/q/16429736 - 发现那些谷歌搜索“使用 pdo 更新多个列”,如果您想进一步研究。再加上另一个coderexception.com/C1Nm1BHHPWxXUSUX/… - 希望对您有所帮助。

标签: php sql pdo


【解决方案1】:

您不能将占位符用于表名或列名,如果该语句的结构发生更改,它将破坏提前准备语句的目的。

您需要使用正确的列名预先构建您的准备语句,无论您是手动命名、字符串替换还是内爆列名列表。

我现在没有可以测试的环境,但类似于:

//Some random values and DB column names
$arrLocation = array ('Victoria','Washington','Toronto','Halifax','Vancouver');
$arrName     = array ('Sue', 'Bob', 'Marley', 'Tim', 'Fae');
$arrColumn   = array (1 => 'name', 2 => 'age', 3 => 'location');


/* Build column & named placeholders
 * $strSet = '`name` = :name, `age` = :age, `location` = :location';
 */

$strSet = '';
foreach ($arrColumn as $column) {
    $strSet .= "`$column` = :$column, ";
}
$strSet = rtrim($strSet, ', ');

$connection = new PDO($dsn, $user, $pass);

/*
 * Prepared statement then evaluates to:
 * UPDATE `table` SET `name` = :name, `age` = :age, `location` = :location
 *   WHERE `id` = :id;
 */
$stmt = $connection->prepare("UPDATE `table` SET $strSet WHERE `id` = :id;");

$arrChange = array (
  1 => $arrName[(rand(0, count($arrName)-1))],
  2 => rand(0, 30),
  3 => $arrLocation[(rand(0, count($arrLocation)-1))]
);

$idToUpdate = 1;
$stmt->bindParam(':id', $idToUpdate, PDO::PARAM_INT);
foreach($arrChange as $key=>$value) {
    $stmt->bindValue(":$arrColumn[$key]", $value);
}
$stmt->execute();

【讨论】:

  • 也许我很密集,但我不确定你在这里做了什么。您将列名设置为变量而不是占位符,但在准备语句之前滚动浏览了 $strSet 的所有值? (我确实通过将prepare语句放在一个循环中来使代码工作,不幸的是效率不高,但没关系;我只是好奇你到底做了什么)
  • 添加了几个代码 cmets -- 由于占位符不能用于准备好的语句中的表或列,因此在准备好的字符串中构建要评估的 SET 字符串,然后在准备好的字符串中有 4 个命名占位符用过的例子。然后循环要设置的值以绑定要执行的值。
  • bindParam 是一个引用,并在执行时评估变量的值; bindValue 绑定绑定时的值。
  • 啊,太好了。非常感谢。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-19
  • 2013-08-24
  • 2015-01-22
  • 2010-09-23
  • 2015-09-12
  • 2011-04-27
  • 2010-11-29
相关资源
最近更新 更多