Mysql
 sql >> Baza danych >  >> RDS >> Mysql

MySQLi :Wstawianie wielu wierszy za pomocą jednej przygotowanej instrukcji

Możliwe jest przygotowanie zapytania z instrukcją zbiorczego wstawiania, konstruując je w locie, ale wymaga to kilku sztuczek. Najważniejsze bity używają str_pad() do skonstruowania ciągu zapytania o zmiennej długości i przy użyciu call_user_func_array() wywołać bind_param() ze zmienną liczbą parametrów.

function insertBulkPrepared($db, $table, $fields, $types, $values) {
    $chunklength = 500;
    $fieldcount = count($fields);
    $fieldnames = '`'.join('`, `', $fields).'`';
    $prefix = "INSERT INTO `$table` ($fieldnames) VALUES ";
    $params = '(' . str_pad('', 3*$fieldcount - 2, '?, ') . '), ';
    $inserted = 0;

    foreach (array_chunk($values, $fieldcount*$chunklength) as $group) {
        $length = count($group);
        if ($inserted != $length) {
            if ($inserted) $stmt->close();
            $records = $length / $fieldcount;
            $query = $prefix . str_pad('', 3*$length + 2*($records - 1), $params);
            #echo "\n<br>Preparing '" . $query . "'";
            $stmt = $db->prepare($query);
            if (!$stmt) return false;
            $binding = str_pad('', $length, $types);
            $inserted = $length;
        }

        array_unshift($group, $binding);
        #echo "\n<br>Binding " . var_export($group, true);
        $bound = call_user_func_array(array($stmt, 'bind_param'), $group);
        if (!$bound) return false;
        if (!$stmt->execute()) return false;
    }

    if ($inserted) $stmt->close();
    return true;
}

Ta funkcja pobiera Twój $db jako mysqli na przykład nazwę tabeli, tablicę nazw pól i płaską tablicę odniesień do wartości. Wstawia do 500 rekordów na zapytanie, w miarę możliwości ponownie wykorzystując przygotowane instrukcje. Zwraca true jeśli wszystkie wstawienia się powiodły, lub false jeśli któryś z nich zawiódł. Zastrzeżenia:

  • Nazwy tabel i pól nie mają znaczenia; Pozostawiam tobie, aby upewnić się, że nie zawierają kleszczy. Na szczęście nigdy nie powinny pochodzić z danych wejściowych użytkownika.
  • Jeśli długość $values nie jest nawet wielokrotnością długości $fields , ostatnia porcja prawdopodobnie nie powiedzie się na etapie przygotowań.
  • Podobnie, długość $types parametr powinien odpowiadać długości $fields w większości przypadków, zwłaszcza gdy niektóre z nich się różnią.
  • Nie rozróżnia trzech sposobów na porażkę. Nie śledzi również liczby wstawek, które zakończyły się sukcesem, ani nie próbuje kontynuować po błędzie.

Po zdefiniowaniu tej funkcji przykładowy kod można zastąpić czymś takim jak:

$inserts = array();
for ($j = 0; $j < $abilitiesMax - 2; $j++) {
    $inserts[] = &$abilityArray[$i]['match_id'];
    $inserts[] = &$abilityArray[$i]['player_slot'];
    $inserts[] = &$abilityArray[$i][$j]['ability'];
    $inserts[] = &$abilityArray[$i][$j]['time'];
    $inserts[] = &$abilityArray[$i][$j]['level'];
}

$fields = array('match_id', 'player_slot', 'ability', 'time', 'level');
$result = insertBulkPrepared($db, 'abilities', $fields, 'iiiii', $inserts);
if (!$result) {
    echo "<p>$db->error</p>";
    echo "<p>ERROR: when trying to insert abilities query</p>";
}

Te znaki ampersand są ważne, ponieważ mysqli_stmt::bind_param oczekuje referencji, których nie dostarcza call_user_func_array w najnowszych wersjach PHP.

Nie przekazałeś nam oryginalnego przygotowanego zestawienia, więc prawdopodobnie musisz dostosować nazwy tabel i pól. Wygląda również na to, że Twój kod znajduje się w pętli nad $i; w takim przypadku tylko for pętla musi znajdować się wewnątrz zewnętrznej pętli. Jeśli wyjmiesz inne linie poza pętlę, zużyjesz nieco więcej pamięci, konstruując $inserts tablicy, w zamian za znacznie wydajniejsze wstawianie zbiorcze.

Możliwe jest również przepisanie insertBulkPrepared() zaakceptować wielowymiarową tablicę, eliminując jedno źródło potencjalnych błędów, ale to wymaga spłaszczenia tablicy po jej podzieleniu na kawałki.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL DATE_FORMAT '%M' na krótki miesiąc?

  2. Konwersja MySQL ROW_NUMBER() NAD PARTYCJĄ

  3. Procedury składowane, MySQL i PHP

  4. BŁĄD 1406:1406:Dane są za długie dla kolumny, ale nie powinny?

  5. Wyszukiwarka słów Scrabble z symbolami wieloznacznymi