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?

12voto

Wenn Sie andere Parameter haben, können Sie wie folgt vorgehen:

$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$query = 'SELECT *
            FROM table
           WHERE X = :x
             AND id IN(';
$comma = '';
for($i=0; $i<count($ids); $i++){
  $query .= $comma.':p'.$i;       // :p0, :p1, ...
  $comma = ',';
}
$query .= ')';

$stmt = $db->prepare($query);
$stmt->bindValue(':x', 123);  // some value
for($i=0; $i<count($ids); $i++){
  $stmt->bindValue(':p'.$i, $ids[$i]);
}
$stmt->execute();

9voto

Sammaye Punkte 41960

Ich weiß auch, dass dieser Thread alt ist, aber ich hatte ein einzigartiges Problem, bei dem ich beim Konvertieren des bald veralteten mysql-Treibers in den PDO-Treiber eine Funktion erstellen musste, die dynamisch sowohl normale params als auch INs aus demselben param-Array erstellen konnte. Also habe ich dies schnell gebaut:

/**
 * mysql::pdo_query('SELECT * FROM TBL_WHOOP WHERE type_of_whoop IN :param AND siz_of_whoop = :size', array(':param' => array(1,2,3), ':size' => 3))
 *
 * @param $query
 * @param $params
 */
function pdo_query($query, $params = array()){

    if(!$query)
        trigger_error('Could not query nothing');

    // Lets get our IN fields first
    $in_fields = array();
    foreach($params as $field => $value){
        if(is_array($value)){
            for($i=0,$size=sizeof($value);$i<$size;$i++)
                $in_array[] = $field.$i;

            $query = str_replace($field, "(".implode(',', $in_array).")", $query); // Lets replace the position in the query string with the full version
            $in_fields[$field] = $value; // Lets add this field to an array for use later
            unset($params[$field]); // Lets unset so we don't bind the param later down the line
        }
    }

    $query_obj = $this->pdo_link->prepare($query);
    $query_obj->setFetchMode(PDO::FETCH_ASSOC);

    // Now lets bind normal params.
    foreach($params as $field => $value) $query_obj->bindValue($field, $value);

    // Now lets bind the IN params
    foreach($in_fields as $field => $value){
        for($i=0,$size=sizeof($value);$i<$size;$i++)
            $query_obj->bindValue($field.$i, $value[$i]); // Both the named param index and this index are based off the array index which has not changed...hopefully
    }

    $query_obj->execute();

    if($query_obj->rowCount() <= 0)
        return null;

    return $query_obj;
}

Es ist noch nicht getestet, aber die Logik scheint vorhanden zu sein.

Ich hoffe, es hilft jemandem, der sich in der gleichen Lage befindet,

Edit: Nach einigen Tests habe ich herausgefunden:

  • PDO mag kein '.' in ihren Namen (was irgendwie dumm ist, wenn Sie mich fragen)
  • bindParam ist die falsche Funktion, bindValue ist die richtige Funktion.

Der Code wurde zu einer funktionierenden Version bearbeitet.

7voto

Eine kleine Bearbeitung über den Code von Schnalle

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids)-1, '?'));

$db   = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

//implode(',', array_fill(0, count($ids)-1), '?')); 
//'?' this should be inside the array_fill
//$stmt->bindValue(($k+1), $in); 
// instead of $in, it should be $id

6voto

Ryan Bair Punkte 2616

Welche Datenbank verwenden Sie? In PostgreSQL verwende ich gerne ANY(array). Um also Ihr Beispiel wiederzuverwenden:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

Leider ist dies nicht wirklich portabel.

Bei anderen Datenbanken müssen Sie sich Ihre eigene Magie ausdenken, wie andere bereits erwähnt haben. Sie sollten diese Logik in einer Klasse/Funktion unterbringen, um sie in Ihrem Programm wiederverwendbar zu machen. Werfen Sie einen Blick auf die Kommentare zu mysql_query Seite auf PHP.NET für weitere Gedanken zu diesem Thema und Beispiele für dieses Szenario.

6voto

Cave Johnson Punkte 6131

Wenn die Spalte nur ganze Zahlen enthalten kann, können Sie wahrscheinlich ohne Platzhalter auskommen und die IDs direkt in die Abfrage eingeben. Sie müssen nur alle Werte des Arrays in Ganzzahlen umwandeln. Etwa so:

$listOfIds = implode(',',array_map('intval', $ids));
$stmt = $db->prepare(
    "SELECT *
     FROM table
     WHERE id IN($listOfIds)"
);
$stmt->execute();

Dies sollte nicht anfällig für SQL-Injection sein.

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