web-dev-qa-db-ger.com

Übergeben eines Arrays an eine Abfrage mithilfe einer WHERE-Klausel

Wenn ich ein Array von ids $galleries = array(1,2,5) gegeben habe, möchte ich eine SQL-Abfrage haben, die die Werte des Arrays in der WHERE-Klausel wie folgt verwendet:

SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */

Wie kann ich diese Abfragezeichenfolge für die Verwendung mit MySQL generieren?

298
Quinn

ACHTUNG! Diese Antwort enthält eine schwerwiegende SQL Injection Sicherheitslücke. Verwenden Sie die hier gezeigten Codebeispiele NICHT, ohne sicherzustellen, dass externe Eingänge bereinigt sind.

$ids = join("','",$galleries);   
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
312
Flavius Stef

Mit PDO:[1]

$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
$statement = $pdo->prepare($select);
$statement->execute($ids);

nter Verwendung von MySQLi [2]

$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
$statement = $mysqli->prepare($select);
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
$statement->execute();
$result = $statement->get_result();

Erläuterung:

Verwenden Sie den SQL-Operator IN(), um zu überprüfen, ob ein Wert in einer bestimmten Liste vorhanden ist.

Im Allgemeinen sieht es so aus:

expr IN (value,...)

Wir können aus unserem Array einen Ausdruck erstellen, der in den () eingefügt wird. Beachten Sie, dass mindestens ein Wert in der Klammer enthalten sein muss, da MySQL sonst einen Fehler zurückgibt. Dies bedeutet, dass sichergestellt wird, dass unser Eingabearray mindestens einen Wert hat. Generieren Sie zur Vermeidung von SQL-Injection-Angriffen zunächst für jedes Eingabeelement einen ?, um eine parametrisierte Abfrage zu erstellen. Hier gehe ich davon aus, dass das Array, das Ihre IDs enthält, $ids heißt:

$in = join(',', array_fill(0, count($ids), '?'));

$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;

Bei einem Eingabearray von drei Elementen sieht $select folgendermaßen aus:

SELECT *
FROM galleries
WHERE id IN (?, ?, ?)

Beachten Sie erneut, dass es für jedes Element im Eingabearray einen ? gibt. Dann verwenden wir PDO oder MySQLi, um die Abfrage wie oben beschrieben vorzubereiten und auszuführen.

Verwenden des Operators IN() mit Zeichenfolgen

Aufgrund der gebundenen Parameter ist es einfach, zwischen Zeichenfolgen und Ganzzahlen zu wechseln. Für PDO ist keine Änderung erforderlich. Ändern Sie für MySQLi str_repeat('i', in str_repeat('s',, wenn Sie Zeichenfolgen überprüfen müssen.

[1] Ich habe einige Fehler bei der Überprüfung der Kürze weggelassen. Sie müssen für jede Datenbankmethode nach den üblichen Fehlern suchen (oder Ihren DB-Treiber so einstellen, dass Ausnahmen ausgelöst werden).

[2]: Benötigt PHP 5.6 oder höher. Wieder habe ich einige Fehler weggelassen, um die Kürze zu überprüfen.

295
Levi Morrison

ints:

$query = "SELECT * FROM `$table` WHERE `$column` IN(".implode(',',$array).")";

streicher:

$query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')";
56
user542568

Vorausgesetzt, Sie bereinigen Ihre Eingaben ordnungsgemäß im Voraus ...

$matches = implode(',', $galleries);

Dann passen Sie einfach Ihre Anfrage an:

SELECT *
FROM galleries
WHERE id IN ( $matches ) 

Zitieren Sie die Werte entsprechend Ihrem Datensatz.

28
AvatarKava

Verwenden:

select id from galleries where id in (1, 2, 5);

Eine einfache for each -Schleife funktioniert.

Flavius ​​/ AvatarKavas Weg ist besser, aber stellen Sie sicher, dass keiner der Array-Werte Kommas enthält.

11

Als Flavius ​​Stefs Antwort können Sie intval() verwenden, um sicherzustellen, dass alle id int-Werte sind:

$ids = join(',', array_map('intval', $galleries));  
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
8
Van-Duyet Le

Für MySQLi mit einer Escape-Funktion:

$ids = array_map(function($a) use($mysqli) { 
    return is_string($a) ? "'".$mysqli->real_escape_string($a)."'" : $a;
  }, $ids);
$ids = join(',', $ids);  
$result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)");

Für gU mit vorbereiteter Anweisung:

$qmarks = implode(',', array_fill(0, count($ids), '?'));
$sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)");
$sth->execute($ids);
8
artoodetoo

Wir sollten uns um SQL Injection Schwachstellen und einen leeren Zustand kümmern. Ich werde beides wie folgt behandeln.

Verwenden Sie für ein reines numerisches Array die entsprechende Typkonvertierung, nämlich intval oder floatval oder doubleval, für jedes Element. Für Zeichenfolgentypen mysqli_real_escape_string() , die auf Wunsch auch auf numerische Werte angewendet werden können. MySQL erlaubt sowohl Zahlen als auch Datumsvarianten als String .

Erstellen Sie eine Funktion ähnlich der folgenden, um die Werte vor der Übergabe an die Abfrage entsprechend zu umgehen:

function escape($string)
{
    // Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
    return mysqli_real_escape_string($db, $string);
}

Eine solche Funktion steht Ihnen höchstwahrscheinlich bereits in Ihrer Anwendung zur Verfügung oder Sie haben bereits eine erstellt.

Bereinigen Sie das String-Array wie folgt:

$values = array_map('escape', $gallaries);

Ein numerisches Array kann durch Verwendung von intval oder floatval oder doubleval bereinigt werden:

$values = array_map('intval', $gallaries);

Dann bauen Sie endlich die Abfragebedingung auf

$where  = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;

oder

$where  = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;

Da das Array manchmal auch leer sein kann, wie $galleries = array();, sollten wir daher beachten, dass IN () keine leere Liste zulässt. Man kann stattdessen auch OR verwenden, aber das Problem bleibt bestehen. Die obige Überprüfung, count($values), soll dasselbe sicherstellen.

Und füge es der letzten Abfrage hinzu:

$query  = 'SELECT * FROM `galleries` WHERE ' . $where;

TIP: Wenn Sie bei einem leeren Array alle Datensätze anzeigen möchten (keine Filterung), anstatt alle Zeilen auszublenden, ersetzen Sie einfach 0 mit 1 im falschen Teil des Ternärs.

6
Izhar Aazmi

Sicherer.

$galleries = array(1,2,5);
array_walk($galleries , 'intval');
$ids = implode(',', $galleries);
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
5
Filipe

Wir können diese "WHERE id IN" -Klausel verwenden, wenn wir das Eingabearray richtig filtern. Etwas wie das:

$galleries = array();

foreach ($_REQUEST['gallery_id'] as $key => $val) {
    $galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
}

Wie im folgenden Beispiel:enter image description here

$galleryIds = implode(',', $galleries);

Das heißt jetzt solltest du sicher $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})"; verwenden

5
Supratim Roy

Die SafeMySQL -Bibliothek von Col. Shrapnel für PHP enthält typbezogene Platzhalter in den parametrisierten Abfragen und einige praktische Platzhalter für die Arbeit mit Arrays. Der Platzhalter ?a erweitert ein Array zu einer durch Kommas getrennten Liste mit maskierten Zeichenfolgen *.

Zum Beispiel:

$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);

* Beachten Sie, dass es keine Rolle spielt, dass SafeMySQL die oben genannten IDs in Zeichenfolgen konvertiert, da MySQL eine automatische Typumwandlung durchführt - Sie erhalten trotzdem das richtige Ergebnis.

5
Mark Amery

Möglicherweise haben Sie die Tabelle texts _(T_ID (int), T_TEXT (text))_ und die Tabelle test _(id (int), var (varchar(255)))_

In insert into test values (1, '1,2,3') ; werden die folgenden Zeilen aus Tabellentexten ausgegeben, in denen T_ID IN (1,2,3):

_SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0
_

Auf diese Weise können Sie eine einfache n2m-Datenbankbeziehung ohne eine zusätzliche Tabelle verwalten und nur SQL verwenden, ohne PHP oder eine andere Programmiersprache verwenden zu müssen.

4
SERJOU

Mehr ein Beispiel:

$galleryIds = [1, '2', 'Vitruvian Man'];
$ids = array_filter($galleryIds, function($n){return (is_numeric($n));});
$ids = implode(', ', $ids);

$sql = "SELECT * FROM galleries WHERE id IN ({$ids})";
// output: 'SELECT * FROM galleries WHERE id IN (1, 2)'

$statement = $pdo->prepare($sql);
$statement->execute();
3
Ricardo Canelas

Neben der Verwendung der IN-Abfrage haben Sie zwei Möglichkeiten, da in einer IN-Abfrage das Risiko einer SQL-Injection-Sicherheitsanfälligkeit besteht. Sie können looping verwenden, um die gewünschten Daten zu erhalten, oder Sie können die Abfrage mit ODER case verwenden

1. SELECT *
      FROM galleries WHERE id=1 or id=2 or id=5;


2. $ids = array(1, 2, 5);
   foreach ($ids as $id) {
      $data[] = SELECT *
                    FROM galleries WHERE id= $id;
   }
2
Gaurav Singh

Unten ist die Methode, die ich verwendet habe, mit PDO mit benannten Platzhaltern für andere Daten. Um die SQL-Injection zu überwinden, filtere ich das Array, um nur die Werte zu akzeptieren, die ganze Zahlen sind, und lehne alle anderen ab.

$owner_id = 123;
$galleries = array(1,2,5,'abc');

$good_galleries = array_filter($chapter_arr, 'is_numeric');

$sql = "SELECT * FROM galleries WHERE owner=:OWNER_ID AND id IN ($good_galleries)";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
    "OWNER_ID" => $owner_id,
));

$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
2
kojow7

Da sich die ursprüngliche Frage auf ein Array von Zahlen bezieht und ich ein Array von Zeichenfolgen verwende, können die angegebenen Beispiele nicht funktionieren.

Ich fand, dass jeder String in einfache Anführungszeichen eingeschlossen werden musste, um mit der Funktion IN() zu arbeiten.

Hier ist meine Lösung

foreach($status as $status_a) {
        $status_sql[] = '\''.$status_a.'\'';
    }
    $status = implode(',',$status_sql);

$sql = mysql_query("SELECT * FROM table WHERE id IN ($status)");

Wie Sie sehen, umschließt die erste Funktion jede Array-Variable mit single quotes (\') und implodiert dann das Array.

HINWEIS: $status enthält keine einfachen Anführungszeichen in der SQL-Anweisung.

Es gibt wahrscheinlich eine schönere Möglichkeit, die Anführungszeichen hinzuzufügen, aber das funktioniert.

2
RJaus

Sicherer Weg ohne PDO:

$ids = array_filter(array_unique(array_map('intval', (array)$ids)));

if ($ids) {
    $query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');';
}
  • (array)$ids Konvertiert die Variable $ids in ein Array
  • array_map Alle Array-Werte in ganze Zahlen umwandeln
  • array_unique Wiederholte Werte entfernen
  • array_filter Nullwerte entfernen
  • implode Verbinde alle Werte mit der IN-Auswahl
1
Lito