sql >> Database >  >> RDS >> Mysql

MySQLi:Meerdere rijen invoegen met één voorbereide instructie

Het is mogelijk om een ​​bulkquery voor het invoegen van een instructie voor te bereiden door deze on-the-fly te construeren, maar er zijn een paar trucjes voor nodig. De belangrijkste bits gebruiken str_pad() om een ​​queryreeks van variabele lengte te maken en call_user_func_array() te gebruiken om bind_param() . aan te roepen met een variabel aantal parameters.

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

Deze functie neemt uw $db als een mysqli instantie, een tabelnaam, een reeks veldnamen en een platte reeks verwijzingen naar waarden. Het voegt maximaal 500 records per zoekopdracht in, waarbij waar mogelijk voorbereide instructies worden hergebruikt. Het retourneert true als alle invoegingen zijn gelukt, of false als een van hen is mislukt. Waarschuwingen:

  • De tabel- en veldnamen zijn niet voorzien van escapetekens; Ik laat het aan jou over om ervoor te zorgen dat ze geen backticks bevatten. Gelukkig mogen ze nooit afkomstig zijn van gebruikersinvoer.
  • Als de lengte van $values is geen even veelvoud van de lengte van $fields , zal het laatste stuk waarschijnlijk mislukken in de voorbereidingsfase.
  • Evenzo is de lengte van de $types parameter moet overeenkomen met de lengte van $fields in de meeste gevallen, vooral wanneer sommige ervan verschillen.
  • Het maakt geen onderscheid tussen de drie manieren om te falen. Het houdt ook niet bij hoeveel invoegingen zijn gelukt, en het probeert ook niet door te gaan na een fout.

Als deze functie is gedefinieerd, kan uw voorbeeldcode worden vervangen door iets als:

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

Die ampersands zijn belangrijk, omdat mysqli_stmt::bind_param verwacht referenties, die niet worden geleverd door call_user_func_array in recente versies van PHP.

U heeft ons niet de originele voorbereide verklaring gegeven, dus u moet waarschijnlijk de tabel- en veldnamen aanpassen. Het lijkt er ook op dat uw code zich in een lus bevindt over $i; in dat geval alleen de for lus moet zich in de buitenste lus bevinden. Als je de andere regels buiten de lus neemt, gebruik je wat meer geheugen bij het construeren van de $inserts array, in ruil voor veel efficiëntere bulk-inserts.

Het is ook mogelijk om insertBulkPrepared() . te herschrijven om een ​​multidimensionale array te accepteren, waarbij één bron van mogelijke fouten wordt geëlimineerd, maar daarvoor moet de array worden afgevlakt nadat deze is opgedeeld.




  1. Hoe de geclusterde index in SQL Server kiezen?

  2. MySQL selecteren string met meerdere speciale tekens

  3. kan handelsmerksymbool niet weergeven in mysql naar html

  4. Hoe kan ik overschakelen van de SQL Server Windows-modus naar de gemengde modus (SQL Server 2008)?