2013-02-25 52 views
18

के साथ बैच एकाधिक पंक्तियों को सम्मिलित करें मैं PHP पीडीओ का उपयोग करके एकाधिक प्रविष्टियां करने के लिए देख रहा हूं।PHP पीडीओ प्लेसहोल्डर

निकटतम जवाब मैं पाया है यह एक

how-to-insert-an-array-into-a-single-mysql-prepared-statement

है हालांकि उदाहरण का उपयोग करता है दिया गया thats ?? असली प्लेसहोल्डर के बजाय।

मैं जगह धारकों के लिए पीएचपी डॉक साइट पर उदाहरण पर ध्यान दिया है

php.net pdo.prepared-statements

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); 
$stmt->bindParam(':name', $name); 
$stmt->bindParam(':value', $value); 

अब कहते हैं कि मैं इसके बाद के संस्करण प्राप्त करने के लिए चाहता था, लेकिन एक सरणी

$valuesToInsert = array(
    0 => array('name' => 'Robert', 'value' => 'some value'), 
    1 => array('name' -> 'Louise', 'value' => 'another value') 
); 
साथ देता है

मैं इसके बारे में पीडीओ और प्रति लेनदेन के एकाधिक आवेषण के साथ कैसे जाउंगा?

मुझे लगता है कि यह एक लूप के साथ शुरू होगा?

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); 

foreach($valuesToInsert as $insertRow){ 

    // now loop through each inner array to match binded values 
    foreach($insertRow as $column => value){ 
     $stmt->bindParam(":{$column}", value); 
    } 
} 
$stmt->execute(); 

हालांकि ऊपर काम नहीं करता है, लेकिन उम्मीद है कि क्या im प्राप्त करने के लिए

+2

आप पाश अंदर निष्पादित करने के लिए की जरूरत है। अन्यथा आप केवल बाध्य पैरामीटर को ओवरराइट कर रहे हैं और केवल अंतिम मूल्य को बाध्यकारी बनाते हैं। –

+1

हालांकि अगर मैं निष्पादित करता हूं तो वह एक समय में डीबी लेनदेन एक पंक्ति करेगा? मैं इसे –

+0

बैच में करने की कोशिश कर रहा हूं, लेकिन यदि आप mysql विस्तारित 'सम्मिलित करें ... मान (...), (...), (...)' सिंटैक्स डालें, यह है आप इसके बारे में कैसे नहीं जाते हैं। आपको एक क्वेरी स्टेटमेंट को पूर्व-निर्माण करना होगा जिसमें आपके द्वारा डाले गए मानों के प्रत्येक सेट के लिए प्लेसहोल्डर है, इसे तैयार करें, पैरामीटर बाध्य करें, फिर निष्पादित करें। आप एक ही तैयार किए गए सम्मिलन को कई बार चलाने के रूप में उतना ही काम करना समाप्त कर देंगे। –

उत्तर

24

सबसे पहले, ? प्रतीकों असली जगह-धारक हैं (अधिकांश चालकों दोनों वाक्यविन्यास, स्थितीय और नामित जगह धारकों उपयोग करने की अनुमति)। दूसरा, तैयार बयान एसक्यूएल कथन में कच्चे इनपुट को इंजेक्ट करने के लिए कुछ भी नहीं है- एसक्यूएल स्टेटमेंट का सिंटैक्स स्वयं अप्रभावित है।

  • कैसे किसी एक क्वेरी के साथ एकाधिक पंक्तियों को सम्मिलित करने के
  • कैसे एसक्यूएल उत्पन्न करने के लिए गतिशील रूप से
  • कैसे नामित जगह-धारकों के साथ तैयार बयानों उपयोग करने के लिए: आप पहले से ही सभी तत्वों को आप की जरूरत है।

यह उन सब को गठबंधन करने के लिए काफी तुच्छ है:

$sql = 'INSERT INTO table (memberID, programID) VALUES '; 
$insertQuery = array(); 
$insertData = array(); 
$n = 0; 
foreach ($data as $row) { 
    $insertQuery[] = '(:memberID' . $n . ', :programID' . $n . ')'; 
    $insertData['memberID' . $n] = $memberid; 
    $insertData['programID' . $n] = $row; 
    $n++; 
} 

if (!empty($insertQuery)) { 
    $sql .= implode(', ', $insertQuery); 
    $stmt = $db->prepare($sql); 
    $stmt->execute($insertData); 
} 
-4

ले जाएँ लूप के अंदर अमल की कोशिश कर प्रदर्शन करेंगे।

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); 
foreach($valuesToInsert as $insertRow) 
{ 
    $stmt->execute($insertRow);  
} 

तो आप इस तरह के सिफारिश की जिस तरह से कोई भी समस्या आती है, तो आप, एक सवाल पूछने की इन कुछ समस्याओं का वर्णन किया है।

+1

मुझे नहीं लगता कि उपरोक्त बैच में ऐसा कर रहा है जैसे यह एक समय में करता है? –

+0

यह बैच डालने वाला नहीं है, आप एक ही एसक्यूएल कथन को प्रति पंक्ति कई बार पुन: उपयोग कर रहे हैं, लेकिन यह अभी भी एक समय में एक ही प्रविष्टि कर रहा है। –

7

मैं तुम्हें InnoDB का उपयोग कर रहे संभालने कर रहा हूँ तो यह जवाब यह है कि इंजन (या किसी अन्य लेन-देन-सक्षम इंजन के लिए मान्य है MyISAM प्रतिसाद नहीं अर्थ शामिल नहीं है)।

डिफ़ॉल्ट रूप से InnoDB ऑटो-प्रतिबद्ध मोड में चलता है। इसका मतलब है कि प्रत्येक क्वेरी को अपने स्वयं के निहित लेनदेन के रूप में माना जाता है।

इसका अनुवाद करने के लिए हमें कुछ प्राणियों को समझने के लिए, इसका मतलब है कि आपके द्वारा जारी की गई प्रत्येक INSERT क्वेरी हार्ड डिस्क को क्वेरी जानकारी लिखने की पुष्टि करके इसे प्रतिबद्ध करने के लिए मजबूर करेगी। यह देखते हुए कि यांत्रिक हार्ड-डिस्क कितनी धीमी हैं क्योंकि प्रति सेकंड इनपुट इनपुट आउटपुट कम है (यदि मुझे गलत नहीं है, तो औसत 300ish आईओ है), इसका मतलब है कि आपके 50 000 प्रश्न होंगे - ठीक है, सुपर धीमी।

तो आप क्या करते हैं? आप एक ही लेनदेन में अपने सभी 50k प्रश्नों को प्रतिबद्ध करते हैं। यह विभिन्न उद्देश्यों के लिए सबसे अच्छा समाधान नहीं हो सकता है लेकिन यह तेज़ होगा।

आप इस तरह यह कार्य करें:

$dbh->beginTransaction(); 

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); 

foreach($valuesToInsert as $insertRow) 
{  
    // now loop through each inner array to match bound values 
    foreach($insertRow as $column => value) 
    { 
     $stmt->bindParam(":$column", value); 
     $stmt->execute(); 
    } 
} 


$dbh->commit(); 
+0

मेरे पास लगभग 50k पंक्तियां डालने के लिए हैं और 25 के बैचों में ऐसा करने जा रही हैं। मैं इस उदाहरण की कोशिश करूंगा क्योंकि ऐसा लगता है कि यह मेरी तलाश में हो सकता है। –

+1

यह उत्तर सही है लेकिन यह MySQL के एकाधिक-सम्मिलित वाक्यविन्यास के बारे में बात नहीं करता है, जो कि मेरे अनुभव में, वास्तव में बड़े बैचों को गति दे सकता है। –

+0

सर्वोत्तम प्रदर्शन के लिए, 'लोड डेटा इन्फाइल' अभी भी सबसे तेज़ विकल्प है और 'लोड डेटा इन्फाइल' के साथ उपयोग की जाने वाली फ़ाइल का निर्माण करना काफी सरल होना चाहिए। मैं इसे उत्तर में जोड़ना भूल गया, और @ अलवारो जी। वीरारियो ने उल्लेख किया - लूप में तैयार कथन को निष्पादित करने से 'INSERT INTO .... VALUES..' तेज है। –

1

समाधान में एक छोटी सी संशोधनों नायब द्वारा प्रदान की
$ stmt-> निष्पादित() भीतरी लूप के बाहर होना चाहिए क्योंकि आप एक या अधिक स्तंभ की जरूरत है कि हो सकता है $ stmt-> execute() को कॉल करने से पहले बाध्य करने के लिए आपको अपवाद मिलेगा "अमान्य पैरामीटर संख्या: बाध्य चर की संख्या टोकन की संख्या से मेल नहीं खाती"।
दूसरा "मूल्य" चर डॉलर के संकेत गायब थे।

function batchinsert($sql,$params){ 
    try { 
       db->beginTransaction(); 

       $stmt = db->prepare($sql); 

       foreach($params as $row) 
       {  
        // now loop through each inner array to match bound values 
        foreach($row as $column => $value) 
        {       
         $stmt->bindParam(":$column", $value);       
        } 
        $stmt->execute(); 
       }          
       db->commit();     

     } catch(PDOExecption $e) { 
      $db->rollback();     
     } 
} 

टेस्ट:

$sql = "INSERT INTO `test`(`name`, `value`) VALUES (:name, :value)" ; 

$data = array();  

array_push($data, array('name'=>'Name1','value'=>'Value1')); 

array_push($data, array('name'=>'Name2','value'=>'Value2')); 

array_push($data, array('name'=>'Name3','value'=>'Value3')); 

array_push($data, array('name'=>'Name4','value'=>'Value4')); 

array_push($data, array('name'=>'Name5','value'=>'Value5')); 

batchinsert($sql,$data); 
-1

आपका कोड वास्तव में ठीक था, लेकिन $stmt->bindParam(":$column", value); में एक समस्या थी यह $stmt->bindValue(":{$column}", $value); होना चाहिए और यह पूरी तरह से काम करेगा। यह भविष्य में दूसरों की सहायता करेगा।

पूर्ण कोड:

foreach($params as $row) 
{ 
    // now loop through each inner array to match bound values 
    foreach($row as $column => $value) 
    { 
     $stmt->bindValue(":{$column}", $value); //EDIT 
    } 
    // Execute statement to add to transaction 
    $stmt->execute(); 
} 
+0

वाक्यविन्यास के इस हिस्से के साथ कोई समस्या नहीं है। आपका सुझाव अधूरा और भ्रामक है। –