我想将PDO INSERT和UPDATE准备好的语句切换到INSERT和ON DUPLICATE KEY UPDATE,因为我认为它比我目前正在做的更有效率,但是我很难搞清楚正确的语法用于命名占位符和bindParam。
我在SO上发现了几个类似的问题,但我是PDO的新手,无法根据我的标准成功调整代码。这是我尝试过的,但它不起作用(它不插入或更新):
try {
$stmt = $conn->prepare('INSERT INTO customer_info (user_id, fname, lname) VALUES(:user_id, :fname, :lname)'
'ON DUPLICATE KEY UPDATE customer_info SET fname= :fname,
lname= :lname
WHERE user_id = :user_id');
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':fname', $_POST['fname'], PDO::PARAM_STR);
$stmt->bindParam(':lname', $_POST['lname'], PDO::PARAM_STR);
$stmt->execute();
}
这是我的代码的简化版本(我有几个查询,每个查询有20-50个字段)。我当前正在更新并检查更新的行数是否大于0,如果没有则运行Insert,并且每个查询都有自己的bindParam语句集。
答案 0 :(得分:16)
您的ON DUPLICATE KEY
语法不正确。
$stmt = $conn->prepare('INSERT INTO customer_info (user_id, fname, lname) VALUES(:user_id, :fname, :lname)
ON DUPLICATE KEY UPDATE fname= :fname2, lname= :lname2');
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':fname', $_POST['fname'], PDO::PARAM_STR);
$stmt->bindParam(':lname', $_POST['lname'], PDO::PARAM_STR);
$stmt->bindParam(':fname2', $_POST['fname'], PDO::PARAM_STR);
$stmt->bindParam(':lname2', $_POST['lname'], PDO::PARAM_STR);
您不需要在SET
子句中放置表名或ON DUPLICATE KEY
,也不需要WHERE
子句(它始终使用副本更新记录)键)。
请参阅http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html
您还遇到了PHP语法错误:您将查询拆分为两个字符串。
更新:
绑定多个参数:
function bindMultiple($stmt, $params, &$variable, $type) {
foreach ($params as $param) {
$stmt->bindParam($param, $variable, $type);
}
}
然后叫它:
bindMultiple($stmt, array(':fname', ':fname2'), $_POST['fname'], PDO::PARAM_STR);
答案 1 :(得分:15)
对于遇到此问题的人来说,下面的恕我直言是正确的答案
注意:此语句假定user_id是表中的KEY。
陈述确实是错的,但接受的答案并不完全正确。
如果您使用相同的值插入和更新(并且不使用不同的值进行更新),则这是更正的查询伪代码:
try {
//optional if your DB driver supports transactions
$conn->beginTransaction();
$stmt = $conn->prepare('INSERT INTO customer_info (user_id, fname, lname) ' .
'VALUES(:user_id, :fname, :lname)' .
'ON DUPLICATE KEY UPDATE fname=VALUES(fname), lname=VALUES(lname)');
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':fname', $_POST['fname'], PDO::PARAM_STR);
$stmt->bindParam(':lname', $_POST['lname'], PDO::PARAM_STR);
$stmt->execute();
//again optional if on MyIASM or DB that doesn't support transactions
$conn->commit();
} catch (PDOException $e) {
//optional as above:
$conn->rollback();
//handle your exception here $e->getMessage() or something
}