【问题标题】:Insert or Update with prepared statements in MySQL在 MySQL 中使用准备好的语句插入或更新
【发布时间】:2012-08-05 10:40:24
【问题描述】:

尝试使用 php 的 pdo 中准备好的语句插入或更新 sql。首先我想到了使用REPLACE INTO 命令,但它给了我一个错误,因为我的索引上有一个外键。读到我必须使用INSERT...ON DUPLICATE KEY UPDATE 语法才能使其工作,但我不清楚如何使用准备好的语句来做到这一点。有什么解决办法吗?谢谢。

sql 是:

$sql="REPLACE INTO fn_currencies(id,short,name,buy,sell,date) VALUES (:id,:short,:name,:buy,:sell,:update)";

UPD:我在 Yii 中进行此查询,该查询使用 PDO 上的个人包装器。 当我使用未命名的参数时,会出现这种类型的错误:

CDbCommand failed to execute the SQL statement: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens. The SQL statement executed was: INSERT INTO `fn_currencies` (id,short,name,buy,sell,date) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE id=?,short=?,name=?,buy=?,sell=?,date=? 

当我使用具有不同名称的命名参数进行插入和更新时,如上所述..我没有收到任何错误,也没有数据插入到我的数据库中。 这是数据库的架构:

CREATE TABLE IF NOT EXISTS `fn_currencies` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `short` varchar(4) NOT NULL,
  `name` varchar(200) NOT NULL,
  `buy` decimal(10,4) NOT NULL,
  `sell` decimal(10,4) NOT NULL,
  `date` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

--
ALTER TABLE `fn_currencies`
  ADD CONSTRAINT `FK_fn_currencies` FOREIGN KEY (`id`) REFERENCES `fn_operations` (`currency_id`);

【问题讨论】:

  • 我怀疑让您感到困惑的是,您不能在准备好的语句中多次使用命名参数。这意味着您必须将其编写为例如INSERT INTO tablename (field1, field2) VALUES (:field1i, :field2i) ON DUPLICATE KEY UPDATE field1 = :field1u, field2 = :field2u,您将不得不复制您发送的数据。它在编程上有点糟糕,但它确实有效(刚刚测试过)
  • @DaveRandom 嗯?重用命名参数效果很好,除非我的记忆力非常糟糕。
  • 它没有给出错误但执行后数据库中没有值..那是什么?
  • @Dave 我很确定我之前写过INSERT INTO foo (bar) VALUES (:baz) ON DUPLICATE UPDATE bar = :baz 之类的代码并且它有效。该陈述可能是错误的或有其他含义。

标签: php sql pdo prepared-statement


【解决方案1】:

感谢 DavaRandom,他指出了我的代码中的一个错误,但这应该可以解决问题。将命名参数替换为 ? 并使用数组合并来动态生成 SQL,如下所示:

$sql="
    insert INTO fn_currencies(id,short,name,buy,sell,date) 
    VALUES (?,?,?,?,?,?)
    on duplicate key update currencies set 
        short=?, name=?, buy=?, sell=?, update=?";
$values=array("id"=>1, "short"=>36, "name"=>'Bazinga', "sell"=>3.67, "date"=>'2012-08-08');
$db->query($sql, array_merge(array_values($values),array_values($values)));

显然这也行得通(请参阅整个页面上关于是/否/可能的 cmets),但上述内容肯定行得通:

$sql="
    insert INTO fn_currencies(id,short,name,buy,sell,date) 
    VALUES (:id,:short,:name,:buy,:sell,:update)
    on duplicate key update currencies set 
        short=:short, name=:name, buy=:buy, sell=:Sell, update=:update";

【讨论】:

  • 您不能在同一个查询中多次使用命名参数。我承认,这确实有点糟糕。您也不需要UPDATE 部分中的表名或SET 关键字。
  • @DaveRandom 嘿,谢谢,但是这些苹果怎么样?
  • 看起来不错 - 虽然如果您查看 Q 上的 cmets,您会发现我已经更正了命名参数点的重用。愚蠢地,我相信了我在手册中读到的内容。但无论哪种方式,使用未命名的参数都可以保证它会起作用。
  • @DaveRandom facepalm,所以我的回答第一次是对的?啊,好吧,至少我知道一种确保它工作的可靠方法:)
  • @VitKos 你确定你的参数都不是空的吗?如果您使用我建议的$values=array(...) 方法,您可以在SQL 执行之前执行print_r($values) 吗?
猜你喜欢
  • 2021-05-18
  • 1970-01-01
  • 2015-02-26
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多