Frage zu SQL-Abfrage einzeln in foreach-Schleife oder als IN Clause

guenter024

Erfahrenes Mitglied
Hallo PHP-Freunde,
wie würdet ihr die SQL-Abfrage gestalten, Variante 1 oder Variante 2?
Was sind eurer Meinung nach Vor- oder Nachteile, was ist die bessere Performance?

PHP:
$example = array('1', '2', '3', '4','5','6', '7', '8', '9', '10', '11', '12', '13');
$limit = 12;

// Variante 1
foreach($example as $key => $value)
{
    if($key < $limit)
    {
        $sql = "SELECT * FROM tabelle WHERE id='".$value."' LIMIT 0,1 ";
        // ...

    }

}

// Variante 2
$clause = '(';
foreach($example as $key => $value)
{
    $clause .= "'".$value."',";
}
$clause = substr($clause, 0, -1);
$clause .= ')';

$sql = "SELECT * FROM tabelle WHERE id IN ".$clause." LIMIT 0,".$limit." ";
// ...

Oder habt ihr noch weitere Ansätze?
 
1) Grundsätzlich: Eine ID sollte eine Zahl sein, kein String.
2) Wozu den Array als Schleife durchgehen? Für so etwas gibt es implode(). Und wenn die ID ein String ist, kann man sich das einbetten in ' auch schenken
3) Woher kommt die Zehlenreihe? Wenn aus der DB: Besser ein SQL mit Unterabfrage definieren als die IDS einzeln auslesen.

Zu deiner Frage: Klar fall 2.
Eine Schlaufe und jedes mal ein Select absetzen ist in der Regel langsamer als einmal ein Select abzusetzen.
PHP:
$example = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
$limit = 12;

$clause = implode(',', $example);

$sql = "SELECT * FROM tabelle WHERE id IN ({$clause}) LIMIT 0, {$limit}";
// gibt: SELECT * FROM tabelle WHERE id IN (1,2,3,4,5,6,7,8,9,10,11,12,13) LIMIT 0, 12
 
Danke für den Input :), sehe das ebenso.
Irgendwie kommt man automatisch in Versuchung, die Variante 1 zu nehmen, weil es auf den 1.Blick einfacher erscheint...

id als Abfragefeld war nur als Beispiel gedacht, könnte auch ein anderes DB-Feld mit VARCHAR-Zeichensatz sein.
An implode hab auch schon gedacht, bei string-Variablen komme ich da aber vermutlich nicht drumherum. Ich denke die eine foreach-Schleife bringt mich aber nicht um ;)
Das Array baut sich auch erst nach und nach auf und kommt nicht aus der DB.
PHP:
$example = array('a', 'b', 'c', 'd','e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm');
$limit = 12;

$sql = "SELECT * FROM abc WHERE buchstabe IN ".mach_in_clause($example)." LIMIT 0,".$limit." ";
function mach_in_clause($array)
{
    $clause = '(';
    foreach($array as $key => $value)
    {
        $clause .= "'".$value."',";
    }
    $clause = substr($clause, 0, -1);
    $clause .= ')';

    return $clause;
}
  
// gibt SELECT * FROM abc WHERE buchstabe IN ('a','b','c','d','e','f','g','h','i','j','k','l','m') LIMIT 0,12

EDIT:
Natürlich müssen die SQL-Abfragevariablen escaped werden!!
 
Aber dan nutze doch die Arrayfunktionen von PHP.
PHP:
function to(&$n){
    return "'{$n}'";
}

$example = array('a', 'b', 'c', 'd','e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm');
$clause = implode(', ', array_map('to', $example));

echo $clause;
// -> $clause = "'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'"
 
Das macht natürlich Sinn :)

Problem war nun noch die Sortierung. Mit der foreach-Schleife wird ja praktisch nacheinander aus der DB abgerufen.
Damit dies so erhalten bleibt habe ich noch ein Order-Construct in die function mit eingebaut.
Bei der IN Abfrage fiel mir jetzt nur ORDER BY FIELD ein.
Das klappt.
PHP:
$clause = mach_in_clause($example, buchstabe, 1);

function mach_in_clause($array, $field, $reverse)
{
    if($reverse == 1) krsort($array);
    $clause = ' '.$field.' IN (';
    $order = ' ORDER BY FIELD ('.$field.',';
    function to(&$n){
        return "'{$n}'";
    }
    $to = implode(',', array_map('to', $array));
    $clause .= $to;
    $clause .= ')';
    $order .= $to;
    $order .= ')';

    return array('in' => $clause, 'order' => $order);

}

$sql = "
SELECT *
FROM abc
WHERE
".$clause['in']."
".$clause['order']."
LIMIT 0,".$limit."
";
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück