Je suis curieux de savoir s'il est possible de lier un tableau de valeurs à un espace réservé à l'aide de PDO. Le cas d'utilisation ici tente de transmettre un tableau de valeurs à utiliser avec une IN()
condition.
J'aimerais pouvoir faire quelque chose comme ça:
<?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();
?>
Et demandez à PDO de lier et de citer toutes les valeurs du tableau.
En ce moment je fais:
<?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();
?>
Ce qui fait certainement le travail, mais je me demande simplement s'il manque une solution intégrée?
Réponses:
je pense que soulmerge a raison. vous devrez construire la chaîne de requête.
correction: dan, tu avais raison. corrigé le code (ne l'a pas testé cependant)
edit: chris (commentaires) et quelqu'un suggèrent que la boucle foreach ...
... pourrait être redondant, donc la
foreach
boucle et le$stmt->execute
pourrait être remplacé par juste ...(encore une fois, je ne l'ai pas testé)
la source
$foreach
etbindValue()
n'est pas requis - exécutez simplement avec le tableau. Par exemple:$stmt->execute($ids);
str_repeat('?,', count($array) - 1). '?';
Pour quelque chose de rapide:
la source
$input_list = substr(str_repeat(',?', count($ids)), 1);
str_repeat('?,', count($ids) - 1) . '?'
. Un appel de fonction en moins.execute
un tableau d'identifiantsEst-il si important d'utiliser une
IN
déclaration? Essayez d'utiliserFIND_IN_SET
op.Par exemple, il y a une requête dans PDO comme ça
Ensuite, il vous suffit de lier un tableau de valeurs, implosé avec une virgule, comme celui-ci
et c'est fait.
UPD: Comme certaines personnes l'ont souligné dans les commentaires de cette réponse, il y a certaines questions qui devraient être explicitées.
FIND_IN_SET
n'utilise pas d'index dans une table, et il n'est pas encore implémenté - voir cet enregistrement dans le suivi des bogues MYSQL . Merci à @BillKarwin pour l'avis.implode
utilisé le symbole virgule comme séparateur. Merci à @VaL pour la note.In fine, si vous n'êtes pas fortement dépendant des index et n'utilisez pas de chaînes avec virgule pour la recherche, ma solution sera beaucoup plus facile, plus simple et plus rapide que les solutions listées ci-dessus.
la source
... FIND_IN_SET(description,'simple,search')
cela fonctionnera, maisFIND_IN_SET(description,'first value,text, with coma inside')
échouera. Ainsi, la fonction recherchera"first value", "text", "with coma inside"
au lieu de celle souhaitée"first value", "text, with coma inside"
Comme je fais beaucoup de requêtes dynamiques, c'est une fonction d'assistance super simple que j'ai faite.
Utilisez-le comme ceci:
Renvoie une chaîne
:id1,:id2,:id3
et met également à jour vos$bindArray
liaisons dont vous aurez besoin au moment d'exécuter votre requête. Facile!la source
La solution d'EvilRygy n'a pas fonctionné pour moi. Dans Postgres, vous pouvez faire une autre solution:
la source
ERROR: operator does not exist: integer = text
. Vous devez au moins ajouter un casting explicite.très propre pour postgres utilise le postgres-array ("{}"):
la source
Voici ma solution:
Notez l'utilisation de array_values. Cela peut résoudre les problèmes de commande clés.
Je fusionnais des tableaux d'ID, puis supprimais les éléments en double. J'avais quelque chose comme:
Et cela échouait.
la source
$original_array
Ajouter des éléments avant le tableau d'origine:array_unshift($original_array, new_unrelated_item);
Ajouter des éléments après le tableau d'origine:array_push($original_array, new_unrelated_item);
Lorsque les valeurs sont liées, les éléments new_unrelated seront placés aux bons emplacements. Cela vous permet de mélanger des éléments matriciels et non matriciels. `J'ai étendu PDO pour faire quelque chose de similaire à ce que suggère stefs, et cela a été plus facile pour moi à long terme:
Vous pouvez l'utiliser comme ceci:
la source
:array
est dans une chaîne dans la requête.if (is_array($data))
une) inutile, mais rend le traitement des données plus précis.En regardant PDO: Constantes prédéfinies, il n'y a pas de PDO :: PARAM_ARRAY dont vous auriez besoin car il est répertorié dans PDOStatement-> bindParam
Je ne pense donc pas que ce soit réalisable.
la source
Lorsque vous avez un autre paramètre, vous pouvez faire comme ceci:
la source
Pour moi, la solution la plus sexy est de construire un tableau associatif dynamique et de l'utiliser
la source
Je me rends également compte que ce fil est ancien, mais j'ai eu un problème unique où, lors de la conversion du pilote mysql qui sera bientôt déconseillé en pilote PDO, j'ai dû créer une fonction qui pourrait générer dynamiquement à la fois des paramètres normaux et des IN à partir du même tableau param. J'ai donc rapidement construit ceci:
Elle n'est pas encore testée mais la logique semble être là.
J'espère que cela aide quelqu'un dans la même position,
Edit: Après quelques tests, j'ai découvert:
Code modifié en version de travail.
la source
Une petite retouche sur le code de Schnalle
la source
Quelle base de données utilisez-vous? Dans PostgreSQL, j'aime utiliser TOUT (tableau). Donc, pour réutiliser votre exemple:
Malheureusement, ce n'est pas portable.
Sur d'autres bases de données, vous devrez créer votre propre magie, comme d'autres l'ont mentionné. Vous voudrez mettre cette logique dans une classe / fonction pour la rendre réutilisable dans votre programme bien sûr. Jetez un œil aux commentaires à la
mysql_query
page sur PHP.NET pour plus de réflexions sur le sujet et des exemples de ce scénario.la source
Après avoir traversé le même problème, je suis allé vers une solution plus simple (bien que toujours pas aussi élégante
PDO::PARAM_ARRAY
):étant donné le tableau
$ids = array(2, 4, 32)
:... etc
Donc, si vous utilisez un tableau de valeurs mixtes, vous aurez besoin de plus de code pour tester vos valeurs avant d'attribuer le type param:
Mais je n'ai pas testé celui-ci.
la source
Comme je sais, il n'y a aucune possibilité de lier un tableau dans une déclaration PDO.
Mais il existe 2 solutions communes:
Utilisez des espaces réservés positionnels (?,?,?,?) Ou des espaces réservés nommés (: id1,: id2,: id3)
$ whereIn = implode (',', array_fill (0, count ($ ids), '?'));
Tableau de devis plus tôt
$ whereIn = array_map (array ($ db, 'quote'), $ ids);
Les deux options sont bonnes et sûres. Je préfère le second car il est plus court et je peux var_dump les paramètres si j'en ai besoin. En utilisant des espaces réservés, vous devez lier des valeurs et à la fin votre code SQL sera le même.
Et la dernière et importante pour moi est d'éviter l'erreur "le nombre de variables liées ne correspond pas au nombre de jetons"
Doctrine, c'est un excellent exemple d'utilisation des espaces réservés positionnels, uniquement parce qu'il a un contrôle interne sur les paramètres entrants.
la source
Si la colonne ne peut contenir que des entiers, vous pouvez probablement le faire sans espaces réservés et simplement mettre les identifiants dans la requête directement. Il vous suffit de convertir toutes les valeurs du tableau en entiers. Comme ça:
Cela ne devrait pas être vulnérable à une injection SQL.
la source
voici ma solution. J'ai également étendu la classe PDO:
Voici un exemple d'utilisation du code ci-dessus:
Laissez-moi savoir ce que vous pensez
la source
BindArrayParam
dans le tableau associatif car vous semblez limiter cela aux entiers.Il n'est pas possible d'utiliser un tableau comme celui-ci dans PDO.
Vous devez créer une chaîne avec un paramètre (ou utiliser?) Pour chaque valeur, par exemple:
:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5
Voici un exemple:
Si vous souhaitez continuer à utiliser
bindParam
, vous pouvez le faire à la place:Si vous souhaitez utiliser des
?
espaces réservés, vous pouvez le faire comme ceci:Si vous ne savez pas si
$ids
est vide, vous devez le tester et gérer ce cas en conséquence (renvoyer un tableau vide, ou renvoyer un objet Null, ou lever une exception, ...).la source
Je suis allé un peu plus loin pour rapprocher la réponse de la question d'origine de l'utilisation des espaces réservés pour lier les paramètres.
Cette réponse devra faire deux boucles à travers le tableau à utiliser dans la requête. Mais cela résout le problème d'avoir d'autres espaces réservés de colonne pour des requêtes plus sélectives.
la source
vous définissez d'abord le nombre de "?" dans la requête, puis par un "pour" envoyer des paramètres comme celui-ci:
la source