sql >> Database teknologi >  >> RDS >> Mysql

MySQLi:Indsættelse af flere rækker med en forberedt erklæring

Det er muligt at forberede en bulk-indsæt-sætningsforespørgsel ved at konstruere den med det samme, men det kræver et par tricks. De vigtigste bits bruger str_pad() at konstruere en forespørgselsstreng med variabel længde og bruge call_user_func_array() at kalde bind_param() med et variabelt antal parametre.

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

Denne funktion tager din $db som en mysqli forekomst, et tabelnavn, en matrix af feltnavne og en flad matrix af referencer til værdier. Den indsætter op til 500 poster pr. forespørgsel, og genbruger forberedte udsagn, når det er muligt. Det returnerer true hvis alle indsættelser lykkedes, eller false hvis nogen af ​​dem mislykkedes. Forbehold:

  • Tabel- og feltnavnene er ikke escaped; Jeg lader det være op til dig at sikre, at de ikke indeholder backticks. Heldigvis bør de aldrig komme fra brugerinput.
  • Hvis længden af ​​$values er ikke et lige multiplum af længden af ​​$fields , vil den sidste del sandsynligvis fejle på forberedelsesstadiet.
  • Længden af ​​$types på samme måde parameter skal matche længden af ​​$fields i de fleste tilfælde, især når nogle af dem er forskellige.
  • Den skelner ikke mellem de tre måder at fejle på. Den holder heller ikke styr på, hvor mange indsættelser der lykkedes, og den forsøger heller ikke at fortsætte efter en fejl.

Med denne funktion defineret kan din eksempelkode erstattes med noget som:

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

Disse og-tegn er vigtige, fordi mysqli_stmt::bind_param forventer referencer, som ikke leveres af call_user_func_array i nyere versioner af PHP.

Du har ikke givet os den oprindelige udarbejdede erklæring, så du skal sandsynligvis justere tabel- og feltnavnene. Det ser også ud til, at din kode sidder inde i en løkke over $i; i så fald kun for løkken skal være inde i den ydre løkke. Hvis du tager de andre linjer uden for løkken, vil du bruge lidt mere hukommelse til at konstruere $inserts array, til gengæld for meget mere effektive bulkskær.

Det er også muligt at omskrive insertBulkPrepared() at acceptere et multidimensionelt array, hvilket eliminerer én kilde til potentiel fejl, men det kræver, at arrayet udflades, efter at det er fragmenteret.




  1. Hent DB-ejers navn i PostgreSql

  2. Opret forbindelse til MySQL på AWS fra lokal maskine

  3. Hele ord matcher med punkttegn i MySQL

  4. MySQLNumberTypeMapping' understøtter ikke værdikonverteringer