php - পিডিও প্রস্তুত একক প্রশ্নের মধ্যে একাধিক সারি সন্নিবেশ




pdo insert (14)

আমি বর্তমানে একক প্রশ্নের মধ্যে মানগুলির একাধিক সারি সন্নিবেশ করতে এই ধরনের এসকিউএলটি মাইএসকিউএল ব্যবহার করছি:

INSERT INTO `tbl` (`key1`,`key2`) VALUES ('r1v1','r1v2'),('r2v1','r2v2'),...

পিডিওর পঠনগুলিতে, প্রস্তুত বিবৃতিগুলির ব্যবহার আমাকে স্ট্যাটিক প্রশ্নের চেয়ে আরও ভালো নিরাপত্তা দিতে পারে।

আমি প্রস্তুত বিবৃতি ব্যবহার করে "এক প্রশ্নের ব্যবহার করে মানগুলির একাধিক সারি সন্নিবেশ করা" জেনারেট করতে পারি কিনা তা জানতে চাই।

যদি হ্যাঁ, আমি কিভাবে এটি বাস্তবায়ন করতে পারি?


$ ডেটা অ্যারের ছোট হলে হার্বার্ট বাল্যাগ্টাসের গ্রহণযোগ্য উত্তর ভাল কাজ করে। বৃহত্তর $ ডেটা অ্যারের সাথে array_merge ফাংশন নিষিদ্ধ ধীর হয়ে যায়। আমার ডেটা অ্যারে তৈরি করার জন্য পরীক্ষা করা ফাইলটি 28 টি কোল এবং এটি প্রায় 80,000 লাইন। চূড়ান্ত স্ক্রিপ্ট সম্পন্ন 41s গ্রহণ।

Array_merge () এর পরিবর্তে $ insert_values ​​তৈরি করতে array_push () ব্যবহার করে ফলে 0.41 গুলি নির্বাহের সময় 100x গতি বৃদ্ধি পেয়েছে

সমস্যাযুক্ত array_merge ():

$insert_values = array();

foreach($data as $d){
 $question_marks[] = '('  . placeholders('?', sizeof($d)) . ')';
 $insert_values = array_merge($insert_values, array_values($d));
}

Array_merge () এর জন্য প্রয়োজনীয়তা দূর করার জন্য, আপনি এর পরিবর্তে নিম্নলিখিত দুটি অ্যারে তৈরি করতে পারেন:

//Note that these fields are empty, but the field count should match the fields in $datafields.
$data[] = array('','','','',... n ); 

//getting rid of array_merge()
array_push($insert_values, $value1, $value2, $value3 ... n ); 

এই অ্যারে তারপর নিম্নরূপ ব্যবহার করা যেতে পারে:

function placeholders($text, $count=0, $separator=","){
    $result = array();
    if($count > 0){
        for($x=0; $x<$count; $x++){
            $result[] = $text;
        }
    }

    return implode($separator, $result);
}

$pdo->beginTransaction();

foreach($data as $d){
 $question_marks[] = '('  . placeholders('?', sizeof($d)) . ')';
}

$sql = "INSERT INTO table (" . implode(",", array_keys($datafield) ) . ") VALUES " . implode(',', $question_marks);

$stmt = $pdo->prepare ($sql);
try {
    $stmt->execute($insert_values);
} catch (PDOException $e){
    echo $e->getMessage();
}
$pdo->commit();

আপনি এই ফাংশনের সাথে একক প্রশ্নের মধ্যে একাধিক সারি সন্নিবেশ করতে পারেন:

function insertMultiple($query,$rows) {
    if (count($rows)>0) {
        $args = array_fill(0, count($rows[0]), '?');

        $params = array();
        foreach($rows as $row)
        {
            $values[] = "(".implode(',', $args).")";
            foreach($row as $value)
            {
                $params[] = $value;
            }
        }

        $query = $query." VALUES ".implode(',', $values);
        $stmt = $PDO->prepare($query);
        $stmt->execute($params);
    }
}

$ সারি মান অ্যারের একটি অ্যারে । আপনার ক্ষেত্রে আপনি ফাংশন কল করবে

insertMultiple("INSERT INTO tbl (`key1`,`key2`)",array(array('r1v1','r1v2'),array('r2v1','r2v2')));

একক প্রশ্নের সাথে একাধিক সারি সন্নিবেশ করার সময় আপনি প্রস্তুত বিবৃতিগুলি ব্যবহার করে এমন সুবিধা পাবেন। সিকিউরিটি!


আমারও একই সমস্যা ছিল এবং এইভাবে আমি নিজের জন্য কাজ করেছি, এবং আমি নিজের জন্য একটি ফাংশন তৈরি করেছি (এবং যদি এটি আপনাকে সাহায্য করে তবে আপনি এটি ব্যবহার করতে পারেন)।

উদাহরণ:

দেশগুলিতে (দেশ, শহর) মূল্যবান (জার্মানি, বার্লিন), (ফ্রান্স, প্যারিস);

$arr1 = Array("Germany", "Berlin");
$arr2 = Array("France", "France");

insertMultipleData("countries", Array($arr1, $arr2));


// Inserting multiple data to the Database.
public function insertMultipleData($table, $multi_params){
    try{
        $db = $this->connect();

        $beforeParams = "";
        $paramsStr = "";
        $valuesStr = "";

        for ($i=0; $i < count($multi_params); $i++) { 

            foreach ($multi_params[$i] as $j => $value) {                   

                if ($i == 0) {
                    $beforeParams .=  " " . $j . ",";
                }

                $paramsStr .= " :"  . $j . "_" . $i .",";                                       
            }

            $paramsStr = substr_replace($paramsStr, "", -1);
            $valuesStr .=  "(" . $paramsStr . "),"; 
            $paramsStr = "";
        }


        $beforeParams = substr_replace($beforeParams, "", -1);
        $valuesStr = substr_replace($valuesStr, "", -1);


        $sql = "INSERT INTO " . $table . " (" . $beforeParams . ") VALUES " . $valuesStr . ";";

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


        for ($i=0; $i < count($multi_params); $i++) { 
            foreach ($multi_params[$i] as $j => &$value) {
                $stmt->bindParam(":" . $j . "_" . $i, $value);                                      
            }
        }

        $this->close($db);
        $stmt->execute();                       

        return true;

    }catch(PDOException $e){            
        return false;
    }

    return false;
}

// Making connection to the Database 
    public function connect(){
        $host = Constants::DB_HOST;
        $dbname = Constants::DB_NAME;
        $user = Constants::DB_USER;
        $pass = Constants::DB_PASS;

        $mysql_connect_str = 'mysql:host='. $host . ';dbname=' .$dbname;

        $dbConnection = new PDO($mysql_connect_str, $user, $pass);
        $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        return $dbConnection;
    }

    // Closing the connection
    public function close($db){
        $db = null;
    }

যদি সন্নিবেশকৃত MultipleData ($ টেবিল, $ মাল্টি_পারাম) TRUE প্রদান করে , আপনার ডেটা আপনার ডেটাবেসে ঢোকানো হয়েছে।


এইভাবে আমি এটা করেছি:

প্রথমে আপনি যে কলামের নামগুলি ব্যবহার করবেন তা সংজ্ঞায়িত করুন, বা এটি ফাঁকা রেখে দিন এবং পডটি আপনি টেবিলের সমস্ত কলাম ব্যবহার করতে অনুমান করতে পারবেন - এ ক্ষেত্রে আপনাকে সারির মানগুলি টেবিলে প্রদর্শিত সঠিক ঠিকানায় জানাতে হবে ।

$cols = 'name', 'middleName', 'eMail';
$table = 'people';

এখন, আপনি ইতিমধ্যে প্রস্তুত একটি দ্বি মাত্রিক অ্যারের আছে। এটি প্রবর্তন করুন এবং আপনার সারি মানগুলির সাথে একটি স্ট্রিং গঠন করুন, যেমন:

foreach ( $people as $person ) {
if(! $rowVals ) {
$rows = '(' . "'$name'" . ',' . "'$middleName'" . ',' .           "'$eMail'" . ')';
} else { $rowVals  = '(' . "'$name'" . ',' . "'$middleName'" . ',' . "'$eMail'" . ')';
}

এখন, আপনি যা ঠিক করেছেন তা চেক ছিল যদি $ সারিগুলি আগে থেকেই সংজ্ঞায়িত করা হয়েছিল এবং যদি না হয় তবে এটি তৈরি করুন এবং সারি মান এবং প্রয়োজনীয় SQL সিনট্যাক্স সংরক্ষণ করুন যাতে এটি একটি বৈধ বিবৃতি হতে পারে। উল্লেখ্য যে স্ট্রিংগুলিকে ডবল উদ্ধৃতি এবং একক উদ্ধৃতিগুলির ভিতরে যেতে হবে, তাই তারা তাৎক্ষণিকভাবে এইভাবে স্বীকৃত হবে।

এটি বাকি বাকি বিবৃতি প্রস্তুত এবং চালানো, যেমন:

$stmt = $db->prepare ( "INSERT INTO $table $cols VALUES $rowVals" );
$stmt->execute ();

পর্যন্ত 2000 সারি পর্যন্ত পরীক্ষা করা হয়েছে, এবং মৃত্যুদন্ড কার্যকর সময় হতাশাজনক। আরও কিছু পরীক্ষা চালানো হবে এবং আমার অবদান রাখতে আরও কিছু আছে।

শুভেচ্ছা।


এখানে আমার সমাধান: https://github.com/sasha-ch/Aura.Sql auraphp / Aura.SQL লাইব্রেরির উপর ভিত্তি করে।

ব্যবহার উদাহরণ:

$q = "insert into t2(id,name) values (?,?), ... on duplicate key update name=name"; 
$bind_values = [ [[1,'str1'],[2,'str2']] ];
$pdo->perform($q, $bind_values);

Bugreports স্বাগত জানাই।


এখানে আমার সহজ পদ্ধতি।

    $values = array();
    foreach($workouts_id as $value){
      $_value = "(".$value.",".$plan_id.")";
      array_push($values,$_value);
    }
    $values_ = implode(",",$values);

    $sql = "INSERT INTO plan_days(id,name) VALUES" . $values_."";
    $stmt = $this->conn->prepare($sql);
    $stmt->execute();

এটা আমার জন্য কাজ করেছে

    $sql = 'INSERT INTO table(pk_pk1,pk_pk2,date,pk_3) VALUES '; 
    $qPart = array_fill(0, count($array), "(?, ?,UTC_TIMESTAMP(),?)");
 $sql .= implode(",", $qPart);
 $stmt =    DB::prepare('base', $sql);
     $i = 1;
     foreach ($array as $value) 
       { 
       $stmt->bindValue($i++, $value);
       $stmt->bindValue($i++, $pk_pk1);
       $stmt->bindValue($i++, $pk_pk2); 
      $stmt->bindValue($i++, $pk_pk3); 
      } 
    $stmt->execute();

এটি মূল্যের জন্য, আমি অনেক ব্যবহারকারীকে নির্বাচিত উত্তর হিসাবে একটি স্ট্রিং প্রশ্নের হিসাবে তৈরি করার পরিবর্তে INSERT বিবৃতিগুলির মাধ্যমে পুনরাবৃত্তি করার প্রস্তাব দিয়েছি। আমি মাত্র দুটি ক্ষেত্র এবং একটি খুব মৌলিক সন্নিবেশ বিবৃতি সঙ্গে একটি সহজ পরীক্ষা চালানোর সিদ্ধান্ত নিয়েছে:

<?php
require('conn.php');

$fname = 'J';
$lname = 'M';

$time_start = microtime(true);
$stmt = $db->prepare('INSERT INTO table (FirstName, LastName) VALUES (:fname, :lname)');

for($i = 1; $i <= 10; $i++ )  {
    $stmt->bindParam(':fname', $fname);
    $stmt->bindParam(':lname', $lname);
    $stmt->execute();

    $fname .= 'O';
    $lname .= 'A';
}


$time_end = microtime(true);
$time = $time_end - $time_start;

echo "Completed in ". $time ." seconds <hr>";

$fname2 = 'J';
$lname2 = 'M';

$time_start2 = microtime(true);
$qry = 'INSERT INTO table (FirstName, LastName) VALUES ';
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?)";

$stmt2 = $db->prepare($qry);
$values = array();

for($j = 1; $j<=10; $j++) {
    $values2 = array($fname2, $lname2);
    $values = array_merge($values,$values2);

    $fname2 .= 'O';
    $lname2 .= 'A';
}

$stmt2->execute($values);

$time_end2 = microtime(true);
$time2 = $time_end2 - $time_start2;

echo "Completed in ". $time2 ." seconds <hr>";
?>

সামগ্রিক কোয়েরি নিজেই মিলিসেকেন্ড বা তার কম গ্রহণ করলে, পরবর্তী (একক স্ট্রিং) প্রশ্ন ক্রমাগত 8 গুণ দ্রুত বা আরও বেশি ছিল। যদি এটি তৈরি করা হয় আরো অনেক কলামে হাজার হাজার সারির আমদানি প্রতিফলিত করে তবে পার্থক্যটি অসাধারণ হতে পারে।


মিঃ বালাগতাসের মতো একই উত্তর, সামান্য পরিষ্কার ...

সাম্প্রতিক সংস্করণ MySQL এবং পিএইচপি PDO মাল্টি-সারি INSERT বিবৃতি সমর্থন করে।

এসকিউএল সংক্ষিপ্ত বিবরণ

এসকিউএল এমন কিছু দেখবে যা 3-কলাম টেবিলে আপনি INSERT করতে চান।

INSERT INTO tbl_name
            (colA, colB, colC)
     VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) [,...]

ON DUPLICATE KEY UPDATE একটি মাল্টি সারি INSERT সঙ্গে এমনকি প্রত্যাশিত হিসাবে কাজ করে; এই যোগ করুন:

ON DUPLICATE KEY UPDATE colA = VALUES(colA), colB = VALUES(colB), colC = VALUES(colC)

পিএইচপি সংক্ষিপ্ত বিবরণ

আপনার পিএইচপি কোড স্বাভাবিক $pdo->prepare($qry) অনুসরণ $pdo->prepare($qry) এবং $stmt->execute($params) পিডিও কল।

$params INSERT যাওয়ার জন্য সমস্ত মানগুলির 1-মাত্রিক অ্যারে হবে

উপরের উদাহরণে, এতে 9 টি উপাদান থাকতে হবে; পিডিও মানগুলির এক সারি হিসাবে 3 এর প্রতিটি সেট ব্যবহার করবে। (3 টি কলামের 3 টি সারি প্রতিটি = 9 টি উপাদান অ্যারে ঢোকানো।)

বাস্তবায়ন

নীচে কোড স্পষ্টতা জন্য লেখা হয়, দক্ষতা নয়। পিএইচপি array_*() ফাংশনগুলি মানচিত্রের উন্নত উপায়ে কাজ করে বা আপনার ডেটা দিয়ে হাঁটতে চান। আপনি লেনদেন ব্যবহার করতে পারেন কিনা সম্ভবত আপনার MySQL টেবিল টাইপ উপর নির্ভর করে।

ধরে নেওয়া যাক:

  • $tblName - সারণির স্ট্রিং নাম INSERT থেকে
  • $colNames - টেবিলের কলামের নামগুলির 1-মাত্রিক অ্যারের এই কলামের নাম বৈধ MySQL কলাম সনাক্তকারী হতে হবে; যদি তারা না হয় তবে ব্যাকটিক্স (``) দিয়ে তাদের পালাও
  • $dataVals - $dataVals -dimensional অ্যারে, যেখানে প্রতিটি উপাদান $dataVals মানের একটি সারির 1-ডি অ্যারে

কোডের উদাহরণ

// setup data values for PDO
// memory warning: this is creating a copy all of $dataVals
$dataToInsert = array();

foreach ($dataVals as $row => $data) {
    foreach($data as $val) {
        $dataToInsert[] = $val;
    }
}

// (optional) setup the ON DUPLICATE column names
$updateCols = array();

foreach ($colNames as $curCol) {
    $updateCols[] = $curCol . " = VALUES($curCol)";
}

$onDup = implode(', ', $updateCols);

// setup the placeholders - a fancy way to make the long "(?, ?, ?)..." string
$rowPlaces = '(' . implode(', ', array_fill(0, count($colNames), '?')) . ')';
$allPlaces = implode(', ', array_fill(0, count($dataVals), $rowPlaces));

$sql = "INSERT INTO $tblName (" . implode(', ', $colNames) . 
    ") VALUES " . $allPlaces . " ON DUPLICATE KEY UPDATE $onDup";

// and then the PHP PDO boilerplate
$stmt = $pdo->prepare ($sql);

try {
   $stmt->execute($dataToInsert);
} catch (PDOException $e){
   echo $e->getMessage();
}

$pdo->commit();

যদিও একটি পুরনো প্রশ্ন সব অবদান আমাকে অনেক সাহায্য করেছে তবে এখানে আমার সমাধান, যা আমার নিজস্ব DbContext ক্লাসের মধ্যে কাজ করে। $rows প্যারামিটারটি কেবল সারি বা মডেলগুলি প্রতিনিধিত্বকারী অ্যাসোসিয়েটেড অ্যারের একটি অ্যারে: field name => insert value

যদি আপনি এমন একটি প্যাটার্ন ব্যবহার করেন যা মডেলগুলি ব্যবহার করে তবে এটি অ্যারের মতো মডেল ডেটা পাস করে চমত্কারভাবে ফিট করে তবে মডেল ক্লাসের মধ্যে একটি ToRowArray পদ্ধতি থেকে বলুন।

দ্রষ্টব্য : এটি বলার অপেক্ষা রাখে না তবে ব্যবহারকারীর কাছে উন্মুক্ত হওয়া বা ব্যবহারকারীর ইনপুটের উপর নির্ভরশীল এই পদ্ধতিতে দেওয়া আর্গুমেন্টগুলিকে অনুমতি দেয় না, সন্নিবেশ মানগুলি ব্যতীত, যা বৈধ এবং স্যানিটাইজড করা হয়েছে। $tableName যুক্তি এবং কলামের নাম কলিং লজিক দ্বারা সংজ্ঞায়িত করা উচিত; উদাহরণস্বরূপ একটি User মডেল ব্যবহারকারী টেবিলে ম্যাপ করা যেতে পারে, যার কলাম তালিকা মডেলের সদস্য ক্ষেত্রগুলিতে ম্যাপ করা হয়েছে।

public function InsertRange($tableName, $rows)
{
    // Get column list
    $columnList = array_keys($rows[0]);
    $numColumns = count($columnList);
    $columnListString = implode(",", $columnList);

    // Generate pdo param placeholders
    $placeHolders = array();

    foreach($rows as $row)
    {
        $temp = array();

        for($i = 0; $i < count($row); $i++)
            $temp[] = "?";

        $placeHolders[] = "(" . implode(",", $temp) . ")";
    }

    $placeHolders = implode(",", $placeHolders);

    // Construct the query
    $sql = "insert into $tableName ($columnListString) values $placeHolders";
    $stmt = $this->pdo->prepare($sql);

    $j = 1;
    foreach($rows as $row)
    {
        for($i = 0; $i < $numColumns; $i++)
        {
            $stmt->bindParam($j, $row[$columnList[$i]]);
            $j++;
        }
    }

    $stmt->execute();
}

যেহেতু এটি এখনও প্রস্তাব করা হয়নি, তাই আমি নিশ্চিত যে লোড ডেটা ইনফিলটি এখনও লোড তথ্য দ্রুত লোড করার উপায় হিসাবে এটি ইন্ডেক্সিং অক্ষম করে, সমস্ত তথ্য সন্নিবেশ করে এবং তারপর সূচীগুলি পুনরায় সক্ষম করে।

একটি csv হিসাবে তথ্য সংরক্ষণ fputcsv মনে রাখা মোটামুটি তুচ্ছ হতে হবে। MyISAM দ্রুততম, তবে আপনি এখনও InnoDB তে বড় পারফরমেন্স পাবেন। অন্যান্য অসুবিধা আছে, তবে আপনি যদি প্রচুর পরিমাণে তথ্য ঢোকাচ্ছেন এবং 100 সারির অধীনে বিরক্ত না হন তবে আমি এই রুটটি দেব।


test.php

<?php
require_once('Database.php');

$obj = new Database();
$table = "test";

$rows = array(
    array(
    'name' => 'balasubramani',
    'status' => 1
    ),
    array(
    'name' => 'balakumar',
    'status' => 1
    ),
    array(
    'name' => 'mani',
    'status' => 1
    )
);

var_dump($obj->insertMultiple($table,$rows));
?>

Database.php

<?php
class Database 
{

    /* Initializing Database Information */

    var $host = 'localhost';
    var $user = 'root';
    var $pass = '';
    var $database = "database";
    var $dbh;

    /* Connecting Datbase */

    public function __construct(){
        try {
            $this->dbh = new PDO('mysql:host='.$this->host.';dbname='.$this->database.'', $this->user, $this->pass);
            //print "Connected Successfully";
        } 
        catch (PDOException $e) {
            print "Error!: " . $e->getMessage() . "<br/>";
            die();
        }
    }
/* Insert Multiple Rows in a table */

    public function insertMultiple($table,$rows){

        $this->dbh->beginTransaction(); // also helps speed up your inserts.
        $insert_values = array();
        foreach($rows as $d){
            $question_marks[] = '('  . $this->placeholders('?', sizeof($d)) . ')';
            $insert_values = array_merge($insert_values, array_values($d));
            $datafields = array_keys($d);
        }

        $sql = "INSERT INTO $table (" . implode(",", $datafields ) . ") VALUES " . implode(',', $question_marks);

        $stmt = $this->dbh->prepare ($sql);
        try {
            $stmt->execute($insert_values);
        } catch (PDOException $e){
            echo $e->getMessage();
        }
        return $this->dbh->commit();
    }

    /*  placeholders for prepared statements like (?,?,?)  */

    function placeholders($text, $count=0, $separator=","){
        $result = array();
        if($count > 0){
            for($x=0; $x<$count; $x++){
                $result[] = $text;
            }
        }

        return implode($separator, $result);
    }

}
?>

অ্যারে ইউনিয়ন এমনকি চেয়ে দ্রুত হওয়া উচিত array_push, তাই কিছু ভালো:

$cumulativeArray += $rowArray; 

প্রস্তুত প্রশ্নটি তৈরি করতে এখানে দেওয়া সমাধানগুলির বেশিরভাগই জটিল হওয়া দরকার। ফাংশন নির্মিত পিএইচপি ব্যবহার করে আপনি সহজে উল্লেখযোগ্য ওভারহেড ছাড়া SQL বিবৃতি crease করতে পারেন।

প্রদত্ত $recordsরেকর্ডগুলির একটি অ্যারে যেখানে প্রতিটি রেকর্ড নিজেই একটি সূচিবদ্ধ অ্যারের (এর আকারে field => value), নিম্নলিখিত ফাংশনটি কেবলমাত্র একটি একক প্রস্তুত বিবৃতি ব্যবহার করে, $tableএকটি PDO সংযোগে প্রদত্ত সারণিতে রেকর্ডগুলি সন্নিবেশ করবে $connection। মনে রাখবেন যে এটি একটি পিএইচপি 5.6+ সমাধান কারণ এই কলটিতে আনপ্যাকিংয়ের যুক্তি ব্যবহার করে array_push:

private function import(PDO $connection, $table, array $records)
{
    $fields = array_keys($records[0]);
    $placeHolders = substr(str_repeat(',?', count($fields)), 1);
    $values = [];
    foreach ($records as $record) {
        array_push($values, ...array_values($record));
    }

    $query = 'INSERT INTO ' . $table . ' (';
    $query .= implode(',', $fields);
    $query .= ') VALUES (';
    $query .= implode('),(', array_fill(0, count($records), $placeHolders));
    $query .= ')';

    $statement = $connection->prepare($query);
    $statement->execute($values);
}




prepared-statement