【问题标题】:Using PDO to UPDATE a value based on its old value within the database使用 PDO 根据数据库中的旧值更新值
【发布时间】:2013-07-03 20:34:00
【问题描述】:

假设我有这样的查询:

$columnstr = "sum";
$valsstr = "sum + 5";

$query = "UPDATE mytable SET $columnstr = ?";
$updatenum = $db->prepare($query);
$updatenum->bindParam(1, $valsstr);
$updatenum->execute();

问题是我认为这行不通,并且由于各种原因我无法完全测试它。 Sum 是一个整数列,但我将一个字符串绑定到它,希望它知道将 5 添加到“sum”。

还需要像这样发送它,因为它并不总是基于列的当前值。

在这种情况下我想发送的查询是:

"UPDATE mytable SET sum=sum+5"

任何意见将不胜感激,谢谢!

【问题讨论】:

  • 您用上一个查询示例回答了您自己的问题
  • 我把这个问题说得很糟糕,你能重新阅读一下,看看它是否更有意义。

标签: php sql pdo sql-update


【解决方案1】:

您不能将查询参数用于表达式。参数仅代替单个标量值。所以并不是说 PDO 不能绑定字符串变量,而是你的字符串“sum+5”将被计算为一个整数,而不是一个 SQL 表达式。 MySQL对“sum+5”的整数值的想法是0。

这不是 PDO 的限制,它是 SQL 的定义方式。无论客户端编程语言或 RDBMS 品牌如何,它都将以相同的方式工作。这是开发人员学习 SQL 的常见障碍。 参数不是字符串插值。 字符串插值发生在prepare() 期间解析 SQL 之前。在解析 SQL 之后,在execute() 期间发送参数。参数值不能强制重新解析 SQL,因此不能在查询中引入额外的表达式语法。这就是它防止 SQL 注入的方式。

如果您输入的字符串可能有时是表达式而其他时候是常量值,那么您的情况就很复杂了。您可以做的最好的事情是编写代码来测试您的输入字符串并进行字符串插值或参数化。

您可以将对象而不是字符串传递给数据库查询方法(PHP 是一种松散类型的语言,这很容易)。如果该值是一个对象,则将其插入到查询字符串中。如果方法参数是标量,则使用参数。

function my_update_method($args) {
  $params = array();
  $query = "UPDATE mytable SET ";
  foreach ($args as $column => $value) {
    if ($value instanceof SQLTerm)
    {
      $query .= "`" . $column . "` = " . $value; /* calls object's __toString() method */
    } else {
      $query .= "`" . $column . "` = ?";
      $params[] = $value;
    }
  }

  $updatenum = $db->prepare($query);
  $updatenum->execute($params);
}

SQLTerm 类只是一个字符串的包装器,它的唯一目的是成为一个对象而不是一个字符串,所以我们可以判断一个值何时是一个要参数化的字符串标量,而不是一个不能被参数化的表达式参数化。

class SQLTerm
{
  protected $string;
  public function __construct($string) {
    $this->string = $string;
  }
  public function __toString() {
    return $this->string;
  }
}

这意味着调用者负责以一种避免 SQL 注入风险的方式创建 SQLTerm 对象。

【讨论】:

  • 非常感谢您花这么多时间深入解释为什么它不起作用。我将您的答案标记为正确答案。
【解决方案2】:

它应该工作。据我所知,只有您直接指定值的列才能被参数化。

以下是有效的 SQL。

UPDATE mytable SET col1=col1+5, col2=?, col3=? WHERE mykey=?

我刚刚在 IBM DB2 9.7 中对其进行了测试,但多年来它一直是有效的语法。

【讨论】:

  • 我意识到我问错了问题,我很傻。我进行了编辑,希望它更有意义或问题更明显。
  • 更多的是关于pdo如何工作的问题。将字符串值绑定到整数列
  • 好的,你要做的是传递一个表达式sum+5作为参数,这是行不通的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-20
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-20
相关资源
最近更新 更多