6

PDO INSERT ve UPDATE tarafından hazırlanan deyimleri INSERT ve ON DUPLICATE KEY UPDATE olarak değiştirmek istiyorum çünkü benden çok daha verimli olacağını düşünüyorum Şu anda yapıyor, ancak adlandırılmış yer tutucuları ve bindParam ile kullanmak için doğru sözdizimi bulmakta sorun yaşıyorum.PDO, INSERT ve ON DUPLICATE ANAHTAR GÜNCELLEŞTİRME ifadeleri için hazırlanmış yer tutucularla hazırlanmış

SO ile ilgili birkaç benzer soru buldum, ancak PDO için yeniyim ve kriterlerimin kodunu başarıyla ayarlayamadım. Bu ne denedim, ama (o eklemek veya güncelleştirmek değil) çalışmaz:

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

Bu benim kod basitleştirilmiş bir versiyonudur (Birkaç sorguları var ve her sorgu arasında yer alır 20 - 50 alan). Şu anda önce güncelleniyorum ve güncellenen satırların sayısının 0'dan büyük olup olmadığını ve ardından Ekle'yi çalıştırmıyor olup olmadığını kontrol ediyorum ve bu sorguların her birinin kendi bindParam ifadeleri kümesi var.

+0

birden fazla yerde aynı yer tutucu tekrar kullanmayın:

Eğer ekleme ve aynı değerler kullanılarak güncellenmesi (ve farklı değerlerle güncellenmiyorsa) ediyorsanız, bu düzeltilmiş sorgu sözde koddur aynı sorguda. PDO bağlantınız istisnalar atacak mı? "BindParam", "bindValue" ya da "execute" üzerinden parametreleri geçirme gereksiniminiz olmadıkça daha iyi bir seçimdir. – DCoder

+0

Aynı yer tutucuyu birden çok yerde kullanmamam gerektiğini söylediğinizde, 2 set bindParam ifadesine ihtiyacım var mı? Şu anda - set (PDOException $ e) {echo 'Error:' ile ayarlanmış. $ e-> getMessage();} - ve bu kod için herhangi bir hata mesajı almıyorum. –

+1

Sorgulamayı deneyin/yakalamak yeterli değildir. [Hata İşleme] 'ye bakın (http://us.php.net/manual/en/pdo.error-handling.php) ve hatalara ilişkin istisnalar atacak şekilde yapılandırın. – DCoder

cevap

15

Sizin ON DUPLICATE KEY sözdizimi yanlış.

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

Sen ON DUPLICATE KEY fıkrada tablo adını veya SET koymak gerekmez ve siz (her zaman yinelenen anahtar ile rekor günceller) bir WHERE maddesi gerekmez.

Ayrıca PHP sözdizimi hatası vardı http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html

Bkz: İki dizeleri içine sorgu bölün.

GÜNCELLEME:

birden fazla parametreye bağlamak için:

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

Sonra diyoruz: Aşağıdaki

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

Bunu açık bir şekilde açıkladığınız için teşekkür ederiz :-) Her parametre için iki bindParam ifadesi oluşturmanın bir yolu var mı? –

+1

Hayır, PDO her yer tutucu için benzersiz olmasını gerektirir. Yer tutucuları ve değişkenleri bir dizi alır bir işlev yazabilirsiniz ve hepsini bağlamak için bir döngü içinde bindParam() 'çağırır. – Barmar

+0

Yanıtın güncellendiğine bakın – Barmar

12

IMHO daha kimsenin bu genelinde gelecek için doğru cevaptır.
Not: Bu ifade, user_id öğesinin tabloda bir KEY olduğunu varsayar.

AÇIKLAMA gerçekten yanlıştı, ancak kabul edilen yanıt tamamen doğru değildi.

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 Parametreleri kullanmanız gerektiğinde 'VALUES()' işlevini kullanmanın daha kolay olduğunu kabul ediyorum. Ama bir yan sorun olarak, Java'da yaptığınız gibi PHP'deki dizinizi kırmanız gerekmez. Çok satırlı bir dizeyi tek bir teklif kümesine koyabilirsiniz. –

+0

@BillKarwin Doğru, ancak şirketimizdeki satırlarımızı 80 veya 100 karaktere sarmayı seviyoruz :-) – Ligemer

İlgili konular