使用PDO根据数据库中的旧值更新值

时间:2013-07-05 17:17:28

标签: php sql pdo sql-update

所以说我有这样的查询:

$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"

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

2 个答案:

答案 0 :(得分:1)

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

以下是有效的SQL。

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

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

答案 1 :(得分:1)

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

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

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

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

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对象。