masukkan beberapa baris melalui array php ke mysql

129

Saya meneruskan dataset besar ke tabel MySQL melalui PHP menggunakan perintah insert dan saya bertanya-tanya apakah mungkin untuk memasukkan sekitar 1000 baris sekaligus melalui kueri selain menambahkan setiap nilai pada akhir string panjang mil lalu mengeksekusinya. Saya menggunakan kerangka CodeIgniter sehingga fungsinya juga tersedia untuk saya.

toofarsideways
sumber
Saya telah memberikan jawaban sesuai dengan pertanyaan Anda untuk menyisipkan beberapa baris Codeigniter.
Somnath Muluk
@SomnathMuluk Terima kasih, namun sudah lama saya tidak perlu menjawab pertanyaan ini
:)
Saya akan merekomendasikan menggunakan fungsi insert_batch CodeIgniter. Jika Anda menggunakan perpustakaan, selalu mencoba memanfaatkan kekuatan dan standar pengkodeannya.
Dewald Els
Saya percaya memasukkan batch adalah cara terbaik untuk melakukan itu melihat tautan stackoverflow.com/questions/27206178/codeigniter-insert-batch
Syed Amir Bukhari

Jawaban:

234

Merakit satu INSERTpernyataan dengan banyak baris jauh lebih cepat di MySQL daripada satu INSERTpernyataan per baris.

Yang mengatakan, sepertinya Anda mungkin mengalami masalah penanganan string di PHP, yang benar-benar masalah algoritma, bukan bahasa. Pada dasarnya, ketika bekerja dengan string besar, Anda ingin meminimalkan penyalinan yang tidak perlu. Terutama, ini berarti Anda ingin menghindari penggabungan. Cara tercepat dan paling efisien memori untuk membangun string besar, seperti untuk memasukkan ratusan baris sekaligus, adalah untuk mengambil keuntungan dari implode()fungsi dan penugasan array.

$sql = array(); 
foreach( $data as $row ) {
    $sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));

Keuntungan dari pendekatan ini adalah Anda tidak menyalin dan menyalin ulang pernyataan SQL yang sejauh ini telah Anda rangkum dengan setiap rangkaian; sebaliknya, PHP melakukan ini sekali dalam implode()pernyataan. Ini adalah kemenangan besar .

Jika Anda memiliki banyak kolom untuk disatukan, dan satu atau lebih sangat panjang, Anda juga bisa membuat lingkaran dalam untuk melakukan hal yang sama dan menggunakan implode()untuk menetapkan klausa nilai ke array luar.

ahli statika
sumber
5
Terima kasih untuk itu! Btw Anda kehilangan braket penutup di akhir fungsi jika ada yang berencana menyalinnya. mysql_real_query ('INSERT INTO table VALUES (teks, kategori)' .implode (','. $ sql));
toofarsideways
3
Terima kasih! Tetap. (Saya sering melakukan itu ...)
staticsan
1
dan permintaan harus benar-benar 'INSERT INTO table (teks, kategori) VALUES' .implode (','. $ sql) sigh 4am coding mengarah ke debugging yang mengerikan :(
toofarsideways
3
Saya percaya kode ini akan menciptakan solusi untuk proyek terbaru saya. Pertanyaan saya di sini adalah, apakah ini aman dari injeksi SQL? Rencana saya adalah untuk beralih mysql_real_escape_stringdengan mysqli_real_escape_stringdan mysql_querydengan mysqli_querykarena saya menggunakan MySQLi dan ini sudah usang pada PHP5. Terimakasih banyak!
wordman
2
mysql_*telah dihapus dari PHP, jadi pastikan untuk menggunakan mysqli_*antarmuka.
Rick James
60

Memasukkan banyak / memasukkan banyak sekarang didukung oleh codeigniter. Saya memiliki masalah yang sama. Meskipun sangat terlambat untuk menjawab pertanyaan, itu akan membantu seseorang. Itu sebabnya menjawab pertanyaan ini.

$data = array(
   array(
      'title' => 'My title' ,
      'name' => 'My Name' ,
      'date' => 'My date'
   ),
   array(
      'title' => 'Another title' ,
      'name' => 'Another Name' ,
      'date' => 'Another date'
   )
);

$this->db->insert_batch('mytable', $data);

// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')
Somnath Muluk
sumber
2
Saya pikir ini adalah cara yang paling direkomendasikan untuk melakukan penyisipan multi baris daripada menggunakan mysql_query. Karena ketika kita menggunakan suatu kerangka kerja, adalah praktik yang baik untuk selalu menggunakan fitur kerangka kerja bawaan.
Praneeth Nidarshan
22

Anda bisa menyiapkan kueri untuk memasukkan satu baris menggunakan kelas mysqli_stmt, dan kemudian mengulangi array data. Sesuatu seperti:

$stmt =  $db->stmt_init();
$stmt->prepare("INSERT INTO mytbl (fld1, fld2, fld3, fld4) VALUES(?, ?, ?, ?)");
foreach($myarray as $row)
{
    $stmt->bind_param('idsb', $row['fld1'], $row['fld2'], $row['fld3'], $row['fld4']);
    $stmt->execute();
}
$stmt->close();

Di mana 'idsb' adalah tipe data yang Anda ikat (int, double, string, blob).

Espresso_Boy
sumber
6
Saya baru-baru ini menjalankan beberapa tolok ukur yang membandingkan insert massal dan menyiapkan pernyataan insert seperti yang disebutkan di sini. Untuk sekitar 500 sisipan, metode sisipan yang disiapkan diselesaikan antara 2,6-4,4 detik, dan metode sisipan massal dalam 0,12-0,35 detik. Saya akan berpikir mysql akan "mem-bulked" pernyataan-pernyataan yang dipersiapkan ini bersama-sama dan berkinerja sama baiknya dengan sisipan massal, tetapi dalam pengaturan default, perbedaan kinerja tampaknya sangat besar. (Btw semua permintaan yang dibandingan menjalankan dalam satu transaksi untuk setiap tes, untuk mencegah komit otomatis)
Motin
16

Saya tahu ini adalah permintaan lama, tetapi saya baru saja membaca dan berpikir saya akan menambahkan apa yang saya temukan di tempat lain:

mysqli di PHP 5 adalah sebuah ojbect dengan beberapa fungsi bagus yang akan memungkinkan Anda untuk mempercepat waktu penyisipan untuk jawaban di atas:

$mysqli->autocommit(FALSE);
$mysqli->multi_query($sqlCombined);
$mysqli->autocommit(TRUE);

Menonaktifkan autocommit ketika memasukkan banyak baris sangat mempercepat penyisipan, jadi matikan, kemudian jalankan seperti yang disebutkan di atas, atau cukup buat string (sqlCombined) yang merupakan banyak pernyataan insert yang dipisahkan oleh semi-titik dua dan multi-kueri akan menanganinya dengan baik.

Semoga ini membantu seseorang menghemat waktu (mencari dan menyisipkan!)

R

Ross Carver
sumber
Ini adalah kesalahan yang saya dapatkan dari ide Anda: "Kesalahan fatal: Panggil ke fungsi anggota otomatis () pada null di /homepages/25/d402746174/htdocs/MoneyMachine/saveQuotes.php on line 30"
user3217883
8

Anda selalu dapat menggunakan mysql LOAD DATA:

LOAD DATA LOCAL INFILE '/full/path/to/file/foo.csv' INTO TABLE `footable` FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n' 

untuk melakukan sisipan massal daripada menggunakan banyak INSERTpernyataan.

vezult
sumber
Saya telah melihat ke dalam itu, tetapi saya perlu memanipulasi data sebelum memasukkannya. Telah diberikan kepada saya sebagai produk Cartesian dari set nilai int 1400 oleh 1400 banyak di antaranya adalah nol. Saya perlu mengkonversikan ke banyak hubungan banyak menggunakan tabel perantara untuk menghemat ruang maka kebutuhan untuk menyisipkan sebagai lawan memasukkan massal
toofarsideways
Anda selalu dapat menghasilkan file csv setelah memanipulasinya dan memanggil pernyataan mysql yang memuat data
Alexander Jardim
Saya pikir itu membantu untuk mengetahui bahwa jalannya adalah lokal untuk klien SQL Anda, dan bukan pada server SQL. File diunggah ke server dan kemudian membacanya. Saya pikir file tersebut harus sudah ada di server, yang bukan itu masalahnya. Jika sudah ada di server, hapus LOCALbitnya.
Kyle
5

Ya, Anda tidak ingin mengeksekusi 1000 panggilan permintaan, tetapi melakukan ini tidak masalah:

$stmt= array( 'array of statements' );
$query= 'INSERT INTO yourtable (col1,col2,col3) VALUES ';
foreach( $stmt AS $k => $v ) {
  $query.= '(' .$v. ')'; // NOTE: you'll have to change to suit
  if ( $k !== sizeof($stmt)-1 ) $query.= ', ';
}
$r= mysql_query($query);

Bergantung pada sumber data Anda, mengisi array mungkin semudah membuka file dan membuang konten ke dalam array melalui file().

bdl
sumber
1
Lebih bersih jika Anda memindahkannya jika di atas kueri dan mengubahnya menjadi sesuatu seperti if ($ k> 0).
cherouvim
@cherouvim ... Ya, Anda benar tentang itu. Terima kasih atas masukan Anda. Ketika saya membaca kembali contoh yang saya berikan, saya gagal memahami maksud Anda. Peduli untuk menguraikan (via pastebin, dll?). Terima kasih -
bdl
3
$query= array(); 
foreach( $your_data as $row ) {
    $query[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $query));
Nikunj Dhimar
sumber
1

Anda dapat melakukannya dengan beberapa cara misalnya di codeigniter

Pertama dengan loop

foreach($myarray as $row)
{
   $data = array("first"=>$row->first,"second"=>$row->sec);
   $this->db->insert('table_name',$data);
}

Kedua - Dengan memasukkan batch

$data = array(
       array(
          'first' => $myarray[0]['first'] ,
          'second' => $myarray[0]['sec'],
        ),
       array(
          'first' => $myarray[1]['first'] ,
          'second' => $myarray[1]['sec'],
        ),
    );

    $this->db->insert_batch('table_name', $data);

Cara ketiga - Dengan melewati beberapa nilai

$sql = array(); 
foreach( $myarray as $row ) {
    $sql[] = '("'.mysql_real_escape_string($row['first']).'", '.$row['sec'].')';
}
mysql_query('INSERT INTO table (first, second) VALUES '.implode(',', $sql));
Kumar Rakesh
sumber
1

Meskipun sudah terlambat untuk menjawab pertanyaan ini. Inilah jawaban saya untuk hal yang sama.

Jika Anda menggunakan CodeIgniter maka Anda dapat menggunakan metode inbuilt yang didefinisikan dalam kelas query_builder.

$ this-> db-> insert_batch ()

Menghasilkan string yang dimasukkan berdasarkan data yang Anda berikan, dan menjalankan kueri. Anda bisa melewatkan array atau objek ke fungsi. Berikut ini contoh menggunakan array:

$data = array(
    array(
            'title' => 'My title',
            'name' => 'My Name',
            'date' => 'My date'
    ),
    array(
            'title' => 'Another title',
            'name' => 'Another Name',
            'date' => 'Another date'
    )

);

$this->db->insert_batch('mytable', $data);
// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'),  ('Another title', 'Another name', 'Another date')

Parameter pertama akan berisi nama tabel, yang kedua adalah array nilai asosiatif.

Anda dapat menemukan detail lebih lanjut tentang query_builder di sini

Abhishek Singh
sumber
0

Saya telah membuat kelas yang melakukan multi-line yang digunakan sebagai berikut:

$pdo->beginTransaction();
$pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10);
$pmi->insertRow($data);
// ....
$pmi->insertRow($data);
$pmi->purgeRemainingInserts();
$pdo->commit();

di mana kelas didefinisikan sebagai berikut:

class PDOMultiLineInserter {
    private $_purgeAtCount;
    private $_bigInsertQuery, $_singleInsertQuery;
    private $_currentlyInsertingRows  = array();
    private $_currentlyInsertingCount = 0;
    private $_numberOfFields;
    private $_error;
    private $_insertCount = 0;

    /**
     * Create a PDOMultiLine Insert object.
     *
     * @param PDO $pdo              The PDO connection
     * @param type $tableName       The table name
     * @param type $fieldsAsArray   An array of the fields being inserted
     * @param type $bigInsertCount  How many rows to collect before performing an insert.
     */
    function __construct(PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) {
        $this->_numberOfFields = count($fieldsAsArray);
        $insertIntoPortion = "REPLACE INTO `$tableName` (`".implode("`,`", $fieldsAsArray)."`) VALUES";
        $questionMarks  = " (?".str_repeat(",?", $this->_numberOfFields - 1).")";

        $this->_purgeAtCount = $bigInsertCount;
        $this->_bigInsertQuery    = $pdo->prepare($insertIntoPortion.$questionMarks.str_repeat(", ".$questionMarks, $bigInsertCount - 1));
        $this->_singleInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks);
    }

    function insertRow($rowData) {
        // @todo Compare speed
        // $this->_currentlyInsertingRows = array_merge($this->_currentlyInsertingRows, $rowData);
        foreach($rowData as $v) array_push($this->_currentlyInsertingRows, $v);
        //
        if (++$this->_currentlyInsertingCount == $this->_purgeAtCount) {
            if ($this->_bigInsertQuery->execute($this->_currentlyInsertingRows) === FALSE) {
                $this->_error = "Failed to perform a multi-insert (after {$this->_insertCount} inserts), the following errors occurred:".implode('<br/>', $this->_bigInsertQuery->errorInfo());
                return false;
            }
            $this->_insertCount++;

            $this->_currentlyInsertingCount = 0;
            $this->_currentlyInsertingRows = array();
        }
        return true;
    }

    function purgeRemainingInserts() {
        while ($this->_currentlyInsertingCount > 0) {
            $singleInsertData = array();
            // @todo Compare speed - http://www.evardsson.com/blog/2010/02/05/comparing-php-array_shift-to-array_pop/
            // for ($i = 0; $i < $this->_numberOfFields; $i++) $singleInsertData[] = array_pop($this->_currentlyInsertingRows); array_reverse($singleInsertData);
            for ($i = 0; $i < $this->_numberOfFields; $i++)     array_unshift($singleInsertData, array_pop($this->_currentlyInsertingRows));

            if ($this->_singleInsertQuery->execute($singleInsertData) === FALSE) {
                $this->_error = "Failed to perform a small-insert (whilst purging the remaining rows; the following errors occurred:".implode('<br/>', $this->_singleInsertQuery->errorInfo());
                return false;
            }
            $this->_currentlyInsertingCount--;
        }
    }

    public function getError() {
        return $this->_error;
    }
}
pengguna3682438
sumber
0

Gunakan masukkan batch dalam codeigniter untuk memasukkan beberapa baris data.

$this->db->insert_batch('tabname',$data_array); // $data_array holds the value to be inserted
aish
sumber
0

Saya telah membuat fungsi sederhana ini yang dapat Anda gunakan dengan mudah. Anda harus melewati nama ($tbl)-tabel, bidang-tabel ($insertFieldsArr)terhadap data yang dimasukkan, array data ($arr).

insert_batch('table',array('field1','field2'),$dataArray);

    function insert_batch($tbl,$insertFieldsArr,$arr){ $sql = array(); 
    foreach( $arr as $row ) {
        $strVals='';
        $cnt=0;
        foreach($insertFieldsArr as $key=>$val){
            if(is_array($row)){
                $strVals.="'".mysql_real_escape_string($row[$cnt]).'\',';
            }
            else{
                $strVals.="'".mysql_real_escape_string($row).'\',';
            }
            $cnt++;
        }
        $strVals=rtrim($strVals,',');
        $sql[] = '('.$strVals.')';
    }

    $fields=implode(',',$insertFieldsArr);
    mysql_query('INSERT INTO `'.$tbl.'` ('.$fields.') VALUES '.implode(',', $sql));
}
Waqas
sumber