6

Chciałbym zmienić przygotowane instrukcje PDO INSERT i UPDATE na INSERT i ON DUPLICATE KEY UPDATE, ponieważ myślę, że będzie to o wiele bardziej wydajne niż to, co ja. Obecnie wykonuję, ale mam problem z określeniem poprawnej składni do użycia z nazwanymi symbolami zastępczymi i bindParam.PDO przygotowało instrukcje dla INSERT i NA DUPLICATE KEY UPDATE z nazwanymi symbolami zastępczymi

Znalazłem kilka podobnych pytań na SO, ale jestem nowy w PDO i nie mogłem z powodzeniem dostosować kodu do moich kryteriów. To co próbowałem, ale to nie działa (nie wkładać lub aktualizacja):

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

To jest uproszczoną wersją mojego kodu (mam kilka pytań, a każde zapytanie ma między 20 - 50 pól). Obecnie aktualizuję najpierw i sprawdzam, czy liczba zaktualizowanych wierszy jest większa od 0, a jeśli nie, to uruchom Wstaw, a każde z tych zapytań ma własny zestaw instrukcji bindParam.

+0

Nie używaj tego samego zastępczy w wielu miejscach w tym samym zapytaniu. Czy twoje połączenie PDO ma ustawione wyjątki? Jeśli nie masz prawdziwej potrzeby 'bindParam', lepszym wyborem jest' bindValue' lub przekazanie parametrów przez 'execute'. – DCoder

+0

Kiedy mówisz, że nie powinienem ponownie używać tego samego symbolu zastępczego w wielu miejscach, masz na myśli, że muszę mieć 2 zestawy instrukcji bindParam? Mam go obecnie ustawiony z - catch (PDOException $ e) {echo "Błąd:". $ e-> getMessage();} - i nie otrzymuję żadnych komunikatów o błędach dla tego kodu. –

+1

Samo wstawienie spróbuj/złap wokół kwerendy, nie wystarczy. Zobacz [Obsługa błędów] (http://us.php.net/manual/en/pdo.error-handling.php) i skonfiguruj go tak, aby zgłaszał wyjątki w przypadku błędów. – DCoder

Odpowiedz

15

Twoja składnia ON DUPLICATE KEY jest niepoprawna.

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

Nie trzeba umieścić nazwę tabeli lub SET w klauzuli ON DUPLICATE KEY, a ty nie potrzebują WHERE klauzulę (zawsze aktualizuje rekord z duplikatu klucza).

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

Miałeś też błąd składni PHP: podzielić kwerendy na dwa ciągi.

UPDATE:

Aby powiązać wiele parametrów:

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

Następnie nazwać:

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

Dziękuję za wyjaśnienie tego tak wyraźnie :-) Czy istnieje sposób na tworzenie dwóch instrukcji bindParam dla każdego parametru? –

+1

Nie, PDO wymaga, aby każdy symbol zastępczy był niepowtarzalny. Możesz napisać funkcję, która pobiera tablicę symboli zastępczych i zmiennych, i wywołuje 'bindParam()' w pętli, aby je wszystkie powiązać. – Barmar

+0

Zobacz aktualizację w odpowiedzi – Barmar

12

IMHO poniżej jest dobrym rozwiązaniem dla każdego, napotykając to ponownie.
Uwaga: w tej instrukcji zakłada się, że id_użytkownika jest KLUCZEM w tabeli.

Oświadczenie rzeczywiście było błędne, ale zaakceptowana odpowiedź nie była całkowicie poprawna.

Jeśli wstawianie i aktualizacja przy użyciu tych samych wartości (a nie aktualizację z różnymi wartościami), to jest zapytanie pseudo-kod poprawione:

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 Zgadzam się, że użycie 'VALUES()' jest łatwiejsze, gdy trzeba użyć parametrów. Ale jako poboczny problem, nie musisz łamać napisu w PHP tak jak w Javie. Możesz umieścić wieloliniowy ciąg znaków w jednym zestawie cytatów. –

+0

@BillKarwin Jest poprawny, ale lubimy owijać nasze linie do 80 lub 100 znaków w naszej firmie :-) – Ligemer

Powiązane problemy