PDO подготовил инструкции для INSERT и On DUPLICATE KEY UPDATE с именованными заполнителями

Я хотел бы переключить PDO INSERT и обновить подготовленные операторы для вставки и обновления дубликатов ключей, так как я думаю, что это будет намного эффективнее, чем то, что я сейчас делаю, но у меня возникли проблемы с правильным синтаксисом для использования с именованными заполнителями и 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.

2 ответов


код 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);

IMHO ниже-Правильный ответ для тех, кто снова столкнется с этим.
Примечание: этот оператор предполагает, что user_id является ключом в таблице.

утверждение действительно было неверным, но принятый ответ не был полностью правильным.

Если вы вставляете и обновляете, используя одни и те же значения (а не обновляете с разными значениями), это исправленный псевдокод запроса:

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
}