PDO Prepared wstawia wiele wierszy w jednym zapytaniu

Obecnie używam tego typu SQL w MySQL do wstawiania wielu wierszy wartości w jednym zapytaniu:

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

Na odczyty na PDO, use przygotowane oświadczenia powinny dać mi lepsze bezpieczeństwo niż statyczne zapytania.

Chciałbym więc wiedzieć, czy możliwe jest wygenerowanie" wstawiania wielu wierszy wartości za pomocą jednego zapytania " przy użyciu gotowych instrukcji.

Jeśli tak, Czy Mogę wiedzieć, jak mogę go wdrożyć?

Author: Francisco de la Peña, 2009-07-24

20 answers

Wstawianie wielu wartości z wyrażeniami przygotowanymi przez PDO

Wstawianie wielu wartości w jednej instrukcji execute. Dlaczego ponieważ według ta strona jest szybsza niż zwykłe wstawki.

$datafields = array('fielda', 'fieldb', ... );

$data[] = array('fielda' => 'value', 'fieldb' => 'value' ....);
$data[] = array('fielda' => 'value', 'fieldb' => 'value' ....);

Więcej wartości danych lub prawdopodobnie masz pętlę, która wypełnia dane.

Z przygotowanymi wstawkami musisz znać pola, do których wstawiasz i liczbę pól, które chcesz utworzyć ? symbole zastępcze do wiązania parametrów.

insert into table (fielda, fieldb, ... ) values (?,?...), (?,?...)....

W zasadzie tak chcemy, aby instrukcja insert wyglądała tak.

Teraz kod:

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(); // also helps speed up your inserts.
$insert_values = array();
foreach($data as $d){
    $question_marks[] = '('  . placeholders('?', sizeof($d)) . ')';
    $insert_values = array_merge($insert_values, array_values($d));
}

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

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

Chociaż w moim teście różnica była tylko 1 s przy użyciu wielu wkładek i zwykłych wkładek przygotowanych z pojedynczą wartością.

 123
Author: Herbert Balagtas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-26 19:46:21

Ta sama odpowiedź Co Pan Balagtas, nieco jaśniejsza...

Najnowsze wersje MySQL i PHP PDO do obsługują instrukcje Wielowierszowe INSERT.

Przegląd SQL

SQL będzie wyglądał mniej więcej Tak, Zakładając 3-kolumnową tabelę, którą chcesz INSERT.

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

ON DUPLICATE KEY UPDATE działa zgodnie z oczekiwaniami nawet z wkładką wielowarstwową; dodaj to:

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

Przegląd PHP

Twój kod PHP będzie podążał za zwykłymi wywołaniami $pdo->prepare($qry) i $stmt->execute($params) PDO.

$params będzie 1-wymiarową tablicą wszystkich wartości, które zostaną przekazane INSERT.

W powyższym przykładzie powinien on zawierać 9 elementów; PDO użyje każdego zbioru 3 jako pojedynczego wiersza wartości. (Wstawianie 3 wierszy po 3 kolumny każdy = tablica 9 elementów.)

Realizacja

Poniższy kod jest napisany dla jasności, a nie efektywności. Pracuj z funkcjami PHP array_*(), aby uzyskać lepsze sposoby mapowania lub przeglądania danych, jeśli chcesz. Czy można oczywiście korzystać z transakcji zależy od typu tabeli MySQL.

Zakładając:

  • $tblName - łańcuchowa nazwa tabeli do wstawienia do
  • $colNames - 1-wymiarowa tablica nazw kolumn tabeli Te nazwy kolumn muszą być poprawnymi identyfikatorami kolumn MySQL; unikaj ich za pomocą backticks ( " ), jeśli nie są
  • $dataVals - tablica mutli-wymiarowa, gdzie każdy element jest tablicą 1-d rzędu wartości do wstawienia

Przykładowy Kod

// 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();
 61
Author: jamesvl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-27 08:41:52

Jeśli to coś warte, widziałem, że wielu użytkowników zaleca iterację za pomocą poleceń INSERT zamiast budowania jako pojedyncze zapytanie łańcuchowe, tak jak wybrana odpowiedź. Postanowiłem przeprowadzić prosty test z dwoma polami i bardzo podstawową instrukcją 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>";
?>

Podczas gdy samo ogólne zapytanie trwało milisekundy lub mniej, to drugie (pojedyncze zapytanie) było konsekwentnie 8 razy szybsze lub więcej. Jeśli to zostało zbudowane, aby powiedzieć odzwierciedlają import tysięcy wierszy na wiele innych kolumny, różnica może być ogromna.

 37
Author: JM4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-31 23:28:33

Przyjęta odpowiedź Herberta Balagtasa działa dobrze, gdy tablica danych $jest mała. Przy większych tablicach $data funkcja array_merge staje się zbyt wolna. Mój plik testowy do utworzenia tablicy danych $ma 28 kol i ma około 80 000 linii. Ostateczny scenariusz zajął 41s .

Użycie array_push () do utworzenia $insert_values zamiast array_merge() spowodowało 100x przyspieszenie z czasem wykonania 0.41 s .

Problematyczne array_merge ():

$insert_values = array();

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

Aby wyeliminować potrzebę array_merge (), możesz zamiast tego zbudować następujące dwie tablice:

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

Te tablice mogą być następnie używane w następujący sposób:

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();
 27
Author: Chris M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-05 04:40:29

To po prostu nie jest sposób, w jaki używasz gotowych wyrażeń.

Jest całkowicie w porządku wstawiać jeden wiersz na zapytanie, ponieważ można wykonać jedną przygotowaną instrukcję wiele razy z różnymi parametrami. W rzeczywistości jest to jedna z największych zalet, ponieważ pozwala wstawić dużą liczbę rzędów w wydajny, bezpieczny i wygodny sposób.

Więc może uda się wdrożyć proponowany przez Ciebie schemat, przynajmniej dla określonej liczby wierszy, ale jest to prawie gwarantowane że nie tego naprawdę chcesz.

 14
Author: sebasgo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-24 09:11:03

Dwa możliwe podejścia:

$stmt = $pdo->prepare('INSERT INTO foo VALUES(:v1_1, :v1_2, :v1_3),
    (:v2_1, :v2_2, :v2_3),
    (:v2_1, :v2_2, :v2_3)');
$stmt->bindValue(':v1_1', $data[0][0]);
$stmt->bindValue(':v1_2', $data[0][1]);
$stmt->bindValue(':v1_3', $data[0][2]);
// etc...
$stmt->execute();

Lub:

$stmt = $pdo->prepare('INSERT INTO foo VALUES(:a, :b, :c)');
foreach($data as $item)
{
    $stmt->bindValue(':a', $item[0]);
    $stmt->bindValue(':b', $item[1]);
    $stmt->bindValue(':c', $item[2]);
    $stmt->execute();
}

Jeśli dane dla wszystkich wierszy są w jednej tablicy, użyłbym drugiego rozwiązania.

 13
Author: Zyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-24 09:28:52

Krótsza odpowiedź: spłaszczyć tablicę danych uporządkowanych przez kolumny, a następnie

//$array = array( '1','2','3','4','5', '1','2','3','4','5');
$arCount = count($array);
$rCount = ($arCount  ? $arCount - 1 : 0);
$criteria = sprintf("(?,?,?,?,?)%s", str_repeat(",(?,?,?,?,?)", $rCount));
$sql = "INSERT INTO table(c1,c2,c3,c4,c5) VALUES$criteria";

Podczas wstawiania około 1000 rekordów nie chcesz mieć pętli przez każdy rekord, aby je wstawić, gdy wszystko, czego potrzebujesz, to liczba wartości.

 7
Author: fyrye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-16 13:47:27

Oto klasa, którą napisałem do wielu wstawek z opcją purge:

<?php

/**
 * $pdo->beginTransaction();
 * $pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10);
 * $pmi->insertRow($data);
 * ....
 * $pmi->insertRow($data);
 * $pmi->purgeRemainingInserts();
 * $pdo->commit();
 *
 */
class PDOMultiLineInserter {
    private $_purgeAtCount;
    private $_bigInsertQuery, $_singleInsertQuery;
    private $_currentlyInsertingRows  = array();
    private $_currentlyInsertingCount = 0;
    private $_numberOfFields;
    private $_error;
    private $_insertCount = 0;

    function __construct(\PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) {
        $this->_numberOfFields = count($fieldsAsArray);
        $insertIntoPortion = "INSERT 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;
    }
}
 3
Author: Pierre Dumuid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-28 03:31:55

Oto moje proste podejście.

    $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();
 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 18:19:10

Tak to zrobiłem:

Najpierw zdefiniuj nazwy kolumn, których będziesz używać, lub pozostaw je puste, a pdo założy, że chcesz użyć wszystkich kolumn w tabeli - w takim przypadku musisz podać wartości wierszy w dokładnej kolejności, w jakiej pojawiają się w tabeli.

$cols = 'name', 'middleName', 'eMail';
$table = 'people';
Załóżmy, że macie już przygotowaną tablicę dwuwymiarową. Iterate it, and construct a string with your row values, as such:
foreach ( $people as $person ) {
if(! $rowVals ) {
$rows = '(' . "'$name'" . ',' . "'$middleName'" . ',' .           "'$eMail'" . ')';
} else { $rowVals  = '(' . "'$name'" . ',' . "'$middleName'" . ',' . "'$eMail'" . ')';
}

Teraz to, co właśnie zrobiłeś, to sprawdzenie, czy $rows zostało już zdefiniowane, a jeśli nie, utwórz go i zachowaj wartości wiersza oraz niezbędną składnię SQL, aby była to poprawna Instrukcja. Należy pamiętać, że łańcuchy znaków powinny znajdować się wewnątrz cudzysłowów podwójnych i pojedynczych, więc zostaną one natychmiast rozpoznane jako takie.

Pozostaje tylko przygotować polecenie i wykonać, jako takie:

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

Przetestowano do 2000 wierszy, a czas wykonania jest ponury. Przeprowadzę jeszcze kilka testów i wrócę tu na wypadek, gdybym miał coś do dodania.

Pozdrawiam.
 1
Author: Théo T. Carranza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-17 19:26:41

Ponieważ nie zostało to jeszcze zasugerowane, jestem prawie pewien, że LOAD DATA INFILE jest nadal najszybszym sposobem ładowania danych, ponieważ wyłącza indeksowanie, wstawia wszystkie dane, a następnie ponownie włącza indeksy-wszystko w jednym żądaniu.

Zapisanie danych jako pliku csv powinno być dość trywialne, pamiętając o fputcsv. MyISAM jest najszybszy, ale w InnoDB nadal osiągasz Duże wyniki. Są też inne wady, więc poszedłbym tą drogą, jeśli wstawiasz dużo danych, a nie przeszkadza ci to poniżej 100 rzędy.

 1
Author: avatarofhope2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-26 02:11:44

Chociaż stare pytanie, wszystkie wkłady bardzo mi pomogły, więc oto moje rozwiązanie, które działa w ramach mojej własnej klasy DbContext. Parametr $rows jest po prostu tablicą tablic asocjacyjnych reprezentujących wiersze lub modele: field name => insert value.

Jeśli używasz wzorca, który używa modeli, pasuje to ładnie, gdy dane modelu są przekazywane jako tablica, powiedzmy z metody ToRowArray wewnątrz klasy modelu.

Notatka: powinno być oczywiste, ale nigdy nie pozwalać na przekazanie argumentów do tego metoda narażona na działanie Użytkownika lub uzależniona od jakichkolwiek danych wejściowych użytkownika, innych niż wartości insert, które zostały zwalidowane i odkażone. Argument $tableName i nazwy kolumn powinny być zdefiniowane przez logikę wywołującą; na przykład model User może być mapowany do tabeli użytkownika, której lista kolumn jest mapowana do pól składowych modelu.

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();
}
 1
Author: Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-19 15:28:17

Możesz wstawić wiele wierszy w jednym zapytaniu za pomocą tej funkcji:

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

$wiersz jest tablicą tablic wartości. W Twoim przypadku wywołałbyś funkcję z

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

Ma to tę zaletę, że używaszgotowych instrukcji , podczas wstawiania wielu wierszy za pomocą jednego zapytania. Ochrona!

 0
Author: Chris Michaelides,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 12:36:57

To zadziałało dla mnie

    $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();
 0
Author: Andre Da Silva Poppi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-28 19:05:48

Oto moje rozwiązanie: https://github.com/sasha-ch/Aura.Sql na podstawie auraphp/Aura.Biblioteka Sql.

Przykład użycia:

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

Zgłoszenia błędów są mile widziane.

 0
Author: sasha-ch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-07 20:30:13

Mój prawdziwy przykład wstawiania wszystkich niemieckich kodów pocztowych do pustej tabeli (aby później dodać nazwy miast):

// obtain column template
$stmt = $db->prepare('SHOW COLUMNS FROM towns');
$stmt->execute();
$columns = array_fill_keys(array_values($stmt->fetchAll(PDO::FETCH_COLUMN)), null);
// multiple INSERT
$postcode = '01000';// smallest german postcode
while ($postcode <= 99999) {// highest german postcode
    $values = array();
    while ($postcode <= 99999) {
        // reset row
        $row = $columns;
        // now fill our row with data
        $row['postcode'] = sprintf('%05d', $postcode);
        // build INSERT array
        foreach ($row as $value) {
            $values[] = $value;
        }
        $postcode++;
        // avoid memory kill
        if (!($postcode % 10000)) {
            break;
        }
    }
    // build query
    $count_columns = count($columns);
    $placeholder = ',(' . substr(str_repeat(',?', $count_columns), 1) . ')';//,(?,?,?)
    $placeholder_group = substr(str_repeat($placeholder, count($values) / $count_columns), 1);//(?,?,?),(?,?,?)...
    $into_columns = implode(',', array_keys($columns));//col1,col2,col3
    // this part is optional:
    $on_duplicate = array();
    foreach ($columns as $column => $row) {
        $on_duplicate[] = $column;
        $on_duplicate[] = $column;
    }
    $on_duplicate = ' ON DUPLICATE KEY UPDATE' . vsprintf(substr(str_repeat(', %s = VALUES(%s)', $count_columns), 1), $on_duplicate);
    // execute query
    $stmt = $db->prepare('INSERT INTO towns (' . $into_columns . ') VALUES' . $placeholder_group . $on_duplicate);//INSERT INTO towns (col1,col2,col3) VALUES(?,?,?),(?,?,?)... {ON DUPLICATE...}
    $stmt->execute($values);
}

Jak widać jest w pełni elastyczny. Nie musisz sprawdzać ilości kolumn ani sprawdzać, na której pozycji znajduje się Twoja kolumna. Wystarczy tylko ustawić dane insert:

    $row['postcode'] = sprintf('%05d', $postcode);

Jestem dumny z niektórych konstruktorów łańcuchów zapytań, ponieważ działają bez ciężkich funkcji tablicowych, takich jak array_merge. Szczególnie vsprintf() był dobrym znaleziskiem.

W końcu musiałem dodać 2x while (), aby uniknąć przekroczenia limitu pamięci. To zależy od limitu pamięci, ale w ogóle jest to dobre ogólne rozwiązanie, aby uniknąć problemów (i mając 10 zapytań jest nadal znacznie lepiej niż 10.000).

 0
Author: mgutt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-05 22:27:39

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

Baza danych.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);
    }

}
?>
 0
Author: sonofkrish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-21 09:24:31

Miałem ten sam problem i to jest jak osiągnąć dla siebie, i zrobiłem funkcję dla siebie dla niego ( i można go użyć, jeśli to pomaga).

Przykład:

INSERT INTO kraje (kraj, miasto) VALUES (Niemcy, Berlin), (Francja, Paryż);

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

Jeśli insertMultipleData ($table, $multi_params) zwraca TRUE , Twoje dane zostały wstawione do twojej bazy danych.

 0
Author: Dardan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-12 14:03:16

Większość rozwiązań podanych tutaj, aby utworzyć przygotowane zapytanie, jest bardziej złożona, niż musi być. Korzystając z wbudowanych funkcji PHP, możesz łatwo utworzyć instrukcję SQL bez znacznych kosztów.

Biorąc pod uwagę $records, tablicę rekordów, w której każdy rekord jest indeksowaną tablicą (w postaci field => value), następująca funkcja wstawi rekordy do podanej tabeli $table, na połączeniu PDO $connection, używając tylko jednej przygotowanej instrukcji. Zauważ, że jest to PHP 5.6+ rozwiązanie ze względu na użycie argumentu unpacking w wywołaniu do 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);
}
 -1
Author: mariano.iglesias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-30 13:15:30

Unia tablicy powinna być jeszcze szybsza niż array_push, więc coś w stylu:

$cumulativeArray += $rowArray; 
 -1
Author: Acim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-29 09:55:40