
Andru
Ich bin neugierig zu wissen, ob es möglich ist, ein Array von Werten mit PDO an einen Platzhalter zu binden. Der Anwendungsfall hier versucht, ein Array von Werten zur Verwendung mit an zu übergeben IN()
Zustand.
Ich würde gerne in der Lage sein, so etwas zu tun:
<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>
Und lassen Sie PDO alle Werte im Array binden und zitieren.
Im Moment mache ich:
<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
$val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute();
?>
Was sicherlich den Job macht, aber ich frage mich nur, ob es eine eingebaute Lösung gibt, die ich vermisse?

stefs
Sie müssen die Abfragezeichenfolge konstruieren.
<?php
$ids = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids), '?'));
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(' . $inQuery . ')'
);
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
$stmt->bindValue(($k+1), $id);
$stmt->execute();
?>
Sowohl Chris (Kommentare) als auch Someoneisintrouble schlugen vor, dass die Foreach-Schleife …
(...)
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
$stmt->bindValue(($k+1), $id);
$stmt->execute();
… könnte überflüssig sein, so die foreach
Schleife und die $stmt->execute
könnte einfach ersetzt werden durch …
<?php
(...)
$stmt->execute($ids);

uɥƃnɐʌuop
Für was schnelles:
//$db = new PDO(...);
//$ids = array(...);
$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);

Tim Tonkonogow
Ist es so wichtig zu verwenden IN
Aussage? Versuchen zu benutzen FIND_IN_SET
op.
Zum Beispiel gibt es eine solche Abfrage in PDO
SELECT * FROM table WHERE FIND_IN_SET(id, :array)
Dann müssen Sie nur ein Array von Werten binden, die mit Kommas implodiert sind, wie dieses hier
$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);
und fertig.
UPD: Wie einige Leute in Kommentaren zu dieser Antwort darauf hingewiesen haben, gibt es einige Probleme, die ausdrücklich erwähnt werden sollten.
FIND_IN_SET
verwendet keinen Index in einer Tabelle und ist noch nicht implementiert – siehe diesen Eintrag im MYSQL-Bugtracker. Danke an @BillKarwin für den Hinweis.
- Sie können keine Zeichenfolge mit Komma als Wert des Arrays für die Suche verwenden. Es ist unmöglich, eine solche Zeichenfolge danach richtig zu analysieren
implode
da Sie das Komma-Symbol als Trennzeichen verwenden. Danke an @VaL für den Hinweis.
Kurz gesagt, wenn Sie nicht stark von Indizes abhängig sind und keine Zeichenfolgen mit Komma für die Suche verwenden, ist meine Lösung viel einfacher, einfacher und schneller als die oben aufgeführten Lösungen.
Ein sehr sauberer Weg für Postgres ist die Verwendung des Postgres-Arrays (“{}”):
$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));
Die Lösung von EvilRygy hat bei mir nicht funktioniert. In Postgres können Sie eine andere Problemumgehung durchführen:
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id = ANY (string_to_array(:an_array, ','))'
);
$stmt->bindParam(':an_array', implode(',', $ids));
$stmt->execute();
Hier ist meine Lösung:
$total_items = count($array_of_items);
$question_marks = array_fill(0, $total_items, '?');
$sql="SELECT * FROM foo WHERE bar IN (" . implode(',', $question_marks ). ')';
$stmt = $dbh->prepare($sql);
$stmt->execute(array_values($array_of_items));
Beachten Sie die Verwendung von array_values. Dadurch können Probleme bei der Schlüsselbestellung behoben werden.
Ich habe Arrays von IDs zusammengeführt und dann doppelte Elemente entfernt. Ich hatte so etwas wie:
$ids = array(0 => 23, 1 => 47, 3 => 17);
Und das scheiterte.
Ich habe PDO erweitert, um etwas Ähnliches zu tun, was stefs vorschlägt, und es war auf lange Sicht einfacher für mich:
class Array_Capable_PDO extends PDO {
/**
* Both prepare a statement and bind array values to it
* @param string $statement mysql query with colon-prefixed tokens
* @param array $arrays associatve array with string tokens as keys and integer-indexed data arrays as values
* @param array $driver_options see php documention
* @return PDOStatement with given array values already bound
*/
public function prepare_with_arrays($statement, array $arrays, $driver_options = array()) {
$replace_strings = array();
$x = 0;
foreach($arrays as $token => $data) {
// just for testing...
//// tokens should be legit
//assert('is_string($token)');
//assert('$token !== ""');
//// a given token shouldn't appear more than once in the query
//assert('substr_count($statement, $token) === 1');
//// there should be an array of values for each token
//assert('is_array($data)');
//// empty data arrays aren't okay, they're a SQL syntax error
//assert('count($data) > 0');
// replace array tokens with a list of value tokens
$replace_string_pieces = array();
foreach($data as $y => $value) {
//// the data arrays have to be integer-indexed
//assert('is_int($y)');
$replace_string_pieces[] = ":{$x}_{$y}";
}
$replace_strings[] = '('.implode(', ', $replace_string_pieces).')';
$x++;
}
$statement = str_replace(array_keys($arrays), $replace_strings, $statement);
$prepared_statement = $this->prepare($statement, $driver_options);
// bind values to the value tokens
$x = 0;
foreach($arrays as $token => $data) {
foreach($data as $y => $value) {
$prepared_statement->bindValue(":{$x}_{$y}", $value);
}
$x++;
}
return $prepared_statement;
}
}
Sie können es wie folgt verwenden:
$db_link = new Array_Capable_PDO($dsn, $username, $password);
$query = '
SELECT *
FROM test
WHERE field1 IN :array1
OR field2 IN :array2
OR field3 = :value
';
$pdo_query = $db_link->prepare_with_arrays(
$query,
array(
':array1' => array(1,2,3),
':array2' => array(7,8,9)
)
);
$pdo_query->bindValue(':value', '10');
$pdo_query->execute();
9936800cookie-checkKann ich ein Array an eine IN()-Bedingung binden?yes
Eine vollständige Anleitung zum Binden eines Arrays an eine IN()-Bedingungeinschließlich des Falls, wenn Sie andere Platzhalter in der Abfrage haben
– Ihr gesunder Menschenverstand
18. April 2017 um 14:10 Uhr
Die Frage wurde als Duplikat dieser Frage geschlossen. Ich habe das Duplikat-Flag umgekehrt, weil diese Frage 4 Jahre älter ist, 4-mal so viele Aufrufe, 3-mal so viele Antworten und 12-mal so viele Punkte hat. Es ist eindeutig das übergeordnete Ziel.
– Mike32
7. März 2020 um 1:58 Uhr
Wer sich das 2020 anschaut: Man könnte es versuchen github.com/morris/dop dafür.
– Morris4
9. Mai 2020 um 16:55 Uhr