Frage

Ich habe ein Problem mit der PDO, die ich hätte wirklich gerne eine Antwort, nachdem er plagt es schon seit einiger Zeit.

Nehmen Sie dieses Beispiel:

Ich bin verbindlich, ein array von IDS, um eine PDO-Anweisung für die Benutzung in einer MySQL-Anweisung.

Das array würde sagen: $values = array(1,2,3,4,5,6,7,8);

Die Datenbank-sichere variable wäre $products = implode(',' $Werte);

So, $Produkte wäre dann eine STRING mit einem Wert von: '1,2,3,4,5,6,7,8'

Das statement würde wie folgt Aussehen:

SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (:products)

Natürlich $Produkte würde gebunden werden, um die Aussage als :Produkte.

Jedoch, wenn die Anweisung kompiliert und Werte gebunden sind, wäre es eigentlich so Aussehen:

SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN ('1,2,3,4,5,6,7,8')

Das problem ist, es ist die Ausführung alles, was sich in der IN der Anweisung als einzelne Zeichenfolge gegeben, die ich vorbereitet habe es als Komma-getrennte Werte, die für die Bindung an die Erklärung.

Was ich wirklich brauche, ist:

SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (1,2,3,4,5,6,7,8)

Nur so kann ich wirklich tun ist, indem die Werte in den string selbst, ohne zu binden, aber ich weiß, für sicher, es muss einen einfacheren Weg, dies zu tun.

War es hilfreich?

Lösung

Dies ist die gleiche Sache wie wurde gebeten, diese Frage: Kann ich binden Sie ein array an eine IN () - Bedingung?

Die Antwort war, dass für eine variable Größe Liste in die in Klausel, müssen Sie zum erstellen der Abfrage selbst.

Jedoch, Sie können die Verwendung der Anführungszeichen, Komma-getrennte Liste mit find_in_set, obwohl für große Datenmengen, dies hätte erhebliche Auswirkungen auf die Leistung, da jeder Wert in die Tabelle zu werfen, um einen char-Typ.

Zum Beispiel:

select users.id
from users
join products
on products.user_id = users.id
where find_in_set(cast(products.id as char), :products)

Oder, als Dritte option, Sie können eine benutzerdefinierte Funktion, spaltet die Komma-getrennte Liste für Sie (cf. http://www.slickdev.com/2008/09/15/mysql-query-real-values-from-delimiter-separated-string-ids/).Dies ist wahrscheinlich die beste option der drei, vor allem wenn Sie haben zu viele Anfragen, die sich auf in(...) Klauseln.

Andere Tipps

Ein guter Weg, um mit dieser situation umzugehen, ist die Verwendung str_pad Platz ? für jeden Wert in der SQL-Abfrage.Dann können Sie das array übergeben von Werten (in Ihrem Fall $values), als argument zu übergeben:

$sql = '
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products.id IN ('.str_pad('',count($values)*2-1,'?,').')
';

$sth = $dbh->prepare($sql);
$sth->execute($values);
$user_ids = $sth->fetchAll();

Auf diese Weise erhalten Sie mehr nutzen aus der Verwendung von prepared statements, anstatt einsetzen die Werte direkt in die SQL.

PS - Das Ergebnis wird Rückkehr doppelte Benutzer-ids, wenn die Produkte mit den angegebenen ids-Freigabe-Benutzer-ids.Wenn Sie möchten, dass nur einmalige Benutzer-ids, schlage ich vor, ändern Sie die erste Zeile der Abfrage SELECT DISTINCT users.id

Die besten vorbereitete Anweisung, die man sich mit in einer situation wie dieser ist so etwas wie die folgenden:

SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (?,?,?,?,?,?,?,?)

Sie würden dann in einer Schleife durch Ihre Werte und binden Sie diese an die vorbereitete Anweisung, zu machen sicher, dass es die gleiche Anzahl von Fragezeichen, die als Werte, die Sie verbindlich sind.

Sie müssen die gleiche Anzahl von ?s in IN als die Anzahl der Werte in Ihrem $Werte array

dies kann leicht getan werden, indem eine Reihe von ?s

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

und verwenden Sie diese in $array in die IN-Klausel

Diese werden dynamisch Ihnen maßgeschneiderte array ?s wie pro Ihre changiing $values array

Sie können dies tun, sehr einfach.Wenn Sie ein array von Werten für Ihre IN () - Anweisung ZB:

$test = array(1,2,3);

Sie können einfach tun

$test = array(1,2,3);
$values = count($test);
$criteria = sprintf("?%s", str_repeat(",?", ($values ? $values-1 : 0)));
//Returns ?,?,?
$sql = sprintf("DELETE FROM table where column NOT IN(%s)", $criteria);
//Returns DELETE FROM table where column NOT IN(?,?,?)
$pdo->sth = prepare($sql);
$pdo->sth->execute($test);

Wenn der Ausdruck beruht auf Benutzereingaben, ohne Bindung, die Werte mit bindValue(), experimentelle SQL könnte nicht werden eine gute Wahl. Aber, können Sie machen es sicher durch überprüfung der syntax der Eingabe mit MySQL REGEXP.

Zum Beispiel:

SELECT *
FROM table
WHERE id IN (3,156)
AND '3,156' REGEXP '^([[:digit:]]+,?)+$'

Hier ist ein Beispiel für das binden einer unbekannten Anzahl von Datensatz-Spalten, um Werte für einen Einsatz.

public function insert($table, array $data)
{
    $sql = "INSERT INTO $table (" . join(',', array_keys($data)) . ') VALUES ('
        . str_repeat('?,', count($data) - 1). '?)';

    if($sth = $this->db->prepare($sql))
    {
        $sth->execute(array_values($data));
        return $this->db->lastInsertId();
    }
}

$id = $db->insert('user', array('name' => 'Bob', 'email' => 'foo@example.com'));

Bitte versuchen wie diese:

WHERE products IN(REPLACE(:products, '\'', ''))

Grüße

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top