2010-09-13 7 views
13

Stellen haben wir eine Abfrage: $ids = array(1,5,18,25)Eine vorbereitete Anweisung, WHERE .. IN (..) `Abfrage und Sortierung - mit MySQL

mit:

SELECT * FROM somewhere WHERE `id` IN(1,5,18,25) ORDER BY `name`; 

und eine Reihe von IDs zu holen Prepared Statements ist es adviced eine Anweisung vorzubereiten und nennen es mehrfach:

$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id`=?;'); 
foreach ($ids as $id){ 
    $stmt->bind_params('i', $id); 
    $stmt->exec(); 
    } 

Aber jetzt werde ich manuell die Ergebnisse sortiert werden. Habe ich schöne Alternativen?

+0

Link Nach Ihnen I zur Verfügung gestellt denke, die Begründung für die Vorbereitung von Anweisungen war die Notwendigkeit, UPDATE, die mehrere Updates in einer Abfrage nicht unterstützt. Während Sie SELECT auswählen, reicht Ihre erste Anfrage aus. –

+0

Ich war überzeugt, dass vorbereitete Aussagen in solchen Fällen nicht gut sind. Die einzige nette Lösung ist, eine Abfrage auszuführen und dieses Array von IDs dort zu sortieren, nicht hier. – kolypto

Antwort

19

Sie könnte es auf diese Weise tun:

$ids = array(1,5,18,25); 

// creates a string containing ?,?,? 
$clause = implode(',', array_fill(0, count($ids), '?')); 


$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id` IN (' . $clause . ') ORDER BY `name`;'); 

call_user_func_array(array($stmt, 'bind_param'), $ids); 
$stmt->execute(); 

// loop through results 

Mit diesem Sie bind_param für jede ID sind anruft und Sie durch mysql getan haben Sortierung.

+1

Ja, aber die schlechte Sache ist, dass die Abfrage nicht wiederverwendet werden kann, so dass es überhaupt nicht nötig ist, sie vorzubereiten :) – kolypto

+1

@o_O Tync: Je weniger Datenbankauslösungen, desto besser. Sie können sich gerne an die PreparedStatement-Einschränkungen halten, aber es wird nicht skaliert, wenn Sie 10/20/50/100/1000 + -Abfragen in derselben Tabelle ausführen müssen. –

+1

Wäre es nicht besser, nur eine Ansicht für diese Aussage zu erstellen, da sie nicht in beiden Richtungen wiederverwendet werden könnte? –

0

Nein, es wird nicht empfohlen, wenn Sie bestimmte Datensätze aus der Datenbank mit ORDER BY Klausel abrufen.

1

Eine Alternative wäre PHP Usort-Funktion für das Ergebnisobjekt zu verwenden, aber das ist "manuell".

sehen: Sort Object in PHP

3

Ich werde eine letztlich langsam & hässliche Lösung hinzufügen, die dennoch Prepared Statements für eine beliebige Anzahl von Array-Elementen verwendet :) 3-Anweisungen sind für jeden Fall universell und überall wiederverwendet werden.

  1. CREATE TEMPORARY TABLE ids ( id INT);
  2. INSERT INTO ids VALUES(?); dies Ihre IDs
  3. SELECT id FROM ids LEFT JOIN .... ; Verwendung von Daten aus anderen Tabellen legen Sie die ids Liste
  4. SELECT id FROM ids wählen ; alles sortieren zurück

Andernfalls müssen Sie IN (?,?,?,.... verwenden oder die Zeilen manuell sortieren. Die beste Idee ist es, einfache MySQL-Abfragen zu verwenden, oder versuchen Sie, die Liste der bereits sortierten IDs in der von Ihnen gewünschten Weise zu erhalten.

0

Haben Sie überlegt, Ihre ursprüngliche Abfrage mit einer JOIN- und WHERE-Klausel neu zu schreiben, um die IDS zu erhalten, die Sie benötigen, um die Notwendigkeit einer WHERE IN-Klausel zu vermeiden? Ich kam mit der gleichen Frage hierher und nachdem ich die möglichen Lösungen überprüft hatte, erkannte ich, dass ein INNER JOIN meine Lösung war.

+0

Das war die interne Logik: Die App benötigt, um N Benutzer von ID, extern zur Verfügung gestellt zu holen. Froh, dass sich dein Fall als nicht so spezifisch herausgestellt hat :) – kolypto

5

Ich glaube, dies ist die einfachste mögliche Antwort lautet:

$ids = [1,2,3,4,5]; 
$pdos = $pdo->prepare("SELECT * FROM somwhere WHERE id IN (:" 
     . implode(',:', array_keys($ids)) . ") ORDER BY id"); 

foreach ($ids as $k => $id) { 
    $pdos->bindValue(":". $k, $id); 
} 

$pdos->execute(); 
$results = $pdos->fetchAll(); 

So lange Ihr Array von Ids keine Schlüssel oder Schlüssel mit ungültigen Zeichen enthalten, wil es funktionieren.

1

haben das gleiche Problem und zusätzlich zu der Antwort von @sled vor 7 Jahren, ist hier eine Möglichkeit, ohne den call_user_func_array(array($stmt, 'bind_param'), $ids); Schritt, aber nur bind_params einmal nennen:

$ids = array(1,5,18,25); 

// creates a string containing ?,?,? 
$bindClause = implode(',', array_fill(0, count($ids), '?')); 
//create a string for the bind param just containing the right amount of iii 
$bindString = str_repeat('i', count($ids)); 

$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id` IN (' . $bindClause . ') ORDER BY `name`;'); 

$stmt->bind_params($bindString, ...$ids); 
$stmt->execute();