6

Vorrei passare PDO INSERT e UPDATE istruzioni preparate su INSERT e ON DUPLICATE KEY UPDATE poiché penso che sarà molto più efficiente di quello che ho ' sto facendo attualmente, ma non riesco a trovare la sintassi corretta da utilizzare con segnaposto e bindParam nominati.Istruzioni PDO preparate per INSERT e ON DUPLICATE KEY UPDATE con segnaposti con nome

Ho trovato diverse domande simili su SO, ma sono nuovo di PDO e non è riuscito ad adattare il codice per i miei criteri. Questo è quello che ho provato, ma non funziona (non inserire o aggiornare):

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(); 
} 

Questa è una versione semplificata del mio codice (ho diverse domande, e ogni query ha tra 20 - 50 campi). Attualmente sto aggiornando per primo e controllando se il numero di righe aggiornate è maggiore di 0 e se non è in esecuzione l'Insert, e ognuna di queste query ha il proprio set di istruzioni bindParam.

+0

Non riutilizzare lo stesso segnaposto in più luoghi nella stessa query. La tua connessione PDO è impostata per generare eccezioni? A meno che tu non abbia una reale necessità di 'bindParam',' bindValue' o il passaggio di parametri attraverso 'execute' è una scelta migliore. – DCoder

+0

Quando dici che non dovrei riutilizzare lo stesso segnaposto in più punti, vuoi dire che devo avere 2 set di istruzioni bindParam? Ce l'ho attualmente impostato con - catch (PDOException $ e) {echo 'Error:'. $ e-> getMessage();} - e non ricevo alcun messaggio di errore per questo codice. –

+1

Il semplice tentativo di aggirare la query non è sufficiente. Vedere [Gestione degli errori] (http://us.php.net/manual/en/pdo.error-handling.php) e configurarlo per generare eccezioni sugli errori. – DCoder

risposta

15

La sintassi ON DUPLICATE KEY non è corretta.

$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);  

Non è necessario mettere il nome della tabella o SET nella clausola ON DUPLICATE KEY, e non hai bisogno di una clausola WHERE (aggiorna sempre il record con la chiave duplicata).

Vedi http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html

Hai anche avuto un errore di sintassi di PHP: di dividere la query in due stringhe.

UPDATE:

di unire più parametri:

function bindMultiple($stmt, $params, &$variable, $type) { 
    foreach ($params as $param) { 
    $stmt->bindParam($param, $variable, $type); 
    } 
} 

Poi lo chiamano:

bindMultiple($stmt, array(':fname', ':fname2'), $_POST['fname'], PDO::PARAM_STR); 
+0

Grazie per averlo spiegato così chiaramente :-) C'è un modo per creare due istruzioni bindParam per ogni parametro? –

+1

No, DOP richiede che ogni segnaposto sia unico. È possibile scrivere una funzione che accetta una matrice di segnaposti e una variabile e chiama 'bindParam()' in un ciclo per collegarli tutti. – Barmar

+0

Vedi l'aggiornamento nella risposta – Barmar

12

IMHO qui di seguito è la risposta giusta per chi viene in questo nuovo.
Nota: questa istruzione presuppone che user_id sia un KEY nella tabella.

La DICHIARAZIONE infatti era errata, ma la risposta accettata non era completamente corretta.

Se si sta inserendo e aggiornando utilizzando gli stessi valori (e non l'aggiornamento con valori diversi), questa è la pseudo-codice di query corretto:

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 
} 
+5

+1 Sono d'accordo che l'utilizzo di 'VALUES()' è più semplice quando è necessario utilizzare i parametri. Ma come problema collaterale, non è necessario spezzare la stringa in PHP come in Java. È possibile inserire una stringa multilinea in un singolo insieme di virgolette. –

+0

@BillKarwin È corretto, ma ci piace avvolgere le nostre linee su 80 o 100 caratteri nella nostra azienda :-) – Ligemer

Problemi correlati