629 Stimmen

Kann ich ein Array an eine IN()-Bedingung in einer PDO-Abfrage binden?

Ich bin neugierig zu wissen, ob es möglich ist, ein Array von Werten an einen Platzhalter mit PDO zu binden. Der Anwendungsfall hier ist der Versuch, ein Array von Werten für die Verwendung mit einer IN() Zustand.

Ich würde gerne so etwas machen können:

<?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 das:

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

Das erfüllt sicherlich seinen Zweck, aber ich frage mich, ob es eine integrierte Lösung gibt, die ich übersehe?

298voto

stefs Punkte 17901

Sie müssen den Abfrage-String 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 somebodyisintrouble 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 dass die foreach Schleife und die $stmt->execute könnte einfach ersetzt werden durch ...

<?php 
  (...)
  $stmt->execute($ids);

193voto

uɥƃnɐʌuop Punkte 12965

Für etwas 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);

48voto

Tim Tonkonogov Punkte 1081

Ist es so wichtig, die IN Aussage? Versuchen Sie zu verwenden FIND_IN_SET op.

Zum Beispiel gibt es eine Abfrage in PDO wie diese

SELECT * FROM table WHERE FIND_IN_SET(id, :array)

Dann brauchen Sie nur ein Array von Werten zu binden, das mit Komma implodiert ist, wie dieses

$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);

und es ist vollbracht.

UPD: Wie einige Leute in Kommentaren zu dieser Antwort anmerkten, gibt es einige Punkte, die explizit genannt werden sollten.

  1. FIND_IN_SET verwendet keinen Index in einer Tabelle und ist immer noch nicht implementiert - siehe dieser Eintrag im MYSQL Bug Tracker . Dank an @BillKarwin für den Hinweis.
  2. Sie können keine Zeichenkette mit Komma als Wert des Arrays für die Suche verwenden. Es ist unmöglich, eine solche Zeichenkette in der richtigen Weise zu parsen, nachdem implode da Sie das Kommasymbol als Trennzeichen verwenden. Danke an @VaL für den Hinweis.

Wenn Sie nicht stark von Indizes abhängig sind und keine Zeichenketten mit Komma für die Suche verwenden, ist meine Lösung viel einfacher, einfacher und schneller als die oben genannten Lösungen.

42voto

prograhammer Punkte 18696

Da ich viele dynamische Abfragen durchführe, habe ich eine super einfache Hilfsfunktion entwickelt.

public static function bindParamArray($prefix, $values, &$bindArray)
{
    $str = "";
    foreach($values as $index => $value){
        $str .= ":".$prefix.$index.",";
        $bindArray[$prefix.$index] = $value;
    }
    return rtrim($str,",");     
}

Verwenden Sie es so:

$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";

Gibt eine Zeichenkette zurück :id1,:id2,:id3 und aktualisiert auch Ihre $bindArray der Bindungen, die Sie benötigen, wenn es Zeit ist, Ihre Abfrage auszuführen. Vorsicht!

21voto

Maik Punkte 474

Eine sehr saubere Methode für Postgres ist die Verwendung von postgres-array ("{}"):

$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X