Que se passe-t-il lorsque vous effectuez une requête SQL où la clause IN
est vide?
Par exemple:
SELECT user WHERE id IN ();
MySQL va-t-il gérer cela comme prévu (c'est-à-dire toujours faux), et sinon, comment mon application peut-elle gérer ce cas lors de la construction dynamique de la clause IN
?
Si j'ai une application où je crée la liste IN
dynamiquement, et qu'elle peut finir vide, ce que je fais parfois est d'initialiser la liste avec une valeur impossible et d'ajouter à cela. Par exemple. s'il s'agit d'une liste de noms d'utilisateurs, je vais commencer par une chaîne vide, car ce n'est pas un nom d'utilisateur possible. S'il s'agit d'un ID auto_increment, j'utiliserai -1 car les valeurs réelles sont toujours positives.
Si cela n'est pas possible car il n'y a pas de valeurs impossibles, vous devez utiliser une conditionnelle pour décider d'inclure ou non l'expression AND column IN ($values)
dans la clause WHERE
.
L'approximation la plus proche de votre requête avec une syntaxe valide est:
SELECT user FROM tbl1 WHERE id IN (SELECT id FROM tbl1 WHERE FALSE);
qui retournera sans condition un jeu de résultats vide. La sous-requête entre crochets renvoie toujours un ensemble vide et, comme je l'ai mentionné précédemment, aucune valeur ne peut être trouvée dans un ensemble vide, car un ensemble vide ne contient aucune valeur.
Cela me donne également 0 résultats:
SELECT id FROM User
WHERE id IN (NULL);
Testé sur MYSQL 5.6
Si vous utilisez AUTO_INCREMENT pour id (1,2,3, ..) et si le tableau est vide, vous pouvez ajouter un élément [0]. Alors il sera
if (empty($arr)) {
$arr[] = 0;
}
SELECT user WHERE id IN (0);
Et il n'y aura pas d'erreur d'analyse mysql. Ce cas est très utile dans les sous-requêtes - lorsque votre requête principale ne dépend pas des résultats de la sous-requête.
Meilleure façon - n'appelez pas la requête si le tableau est vide.
$data = null;
if (!empty($arr)) {
$data = ... call query
}
Utilisez une déclaration toujours fausse
Avant de créer le SQL, vérifiez la taille du tableau. Si la taille est 0, générez l'instruction where comme 1 = 2
, un péché:
SELECT * FROM USERS WHERE name in ()
devient
SELECT * FROM USERS WHERE 1 = 2
Pour "pas dans" sur un tableau vide, générez une instruction toujours vraie comme dans:
SELECT * FROM USERS WHERE name not in ()
devient
SELECT * FROM USERS WHERE 1 = 1
Cela devrait fonctionner pour les requêtes plus complexes comme:
SELECT * FROM USERS WHERE (name in () OR name = 'Alice')
devient
SELECT * FROM USERS WHERE (1 = 2 OR name = 'Alice')
Je suppose que vous devez toujours exécuter la requête lorsque votre IN
est vide; par exemple avec LEFT JOIN ... ON ... AND IN ()
.
Comme vous construisez déjà dynamiquement le IN
dans la couche application, je gérerais le cas vide là-bas.
Voici un exemple de base en PHP
$condition = 'FALSE' // Could feasibly want TRUE under different circumstances
if($values){
$inParams = **dynamically generated IN parameters from $values**;
$condition = 'IN (' . $inParams . ')';
}
$sql = 'SELECT * FROM `user` WHERE '.$condition;
Si vous n'avez pas besoin d'exécuter la requête avec un IN
vide, alors ne le faites pas; épargnez-vous un voyage à la base de données!
NB Au cas où vous ne le seriez pas déjà, je construirais/utiliserais une fonction qui irait dans le sens et lierait correctement vos paramètres IN
, plutôt que de simplement les concaténer bruts dans le SQL. Cela vous donnera une certaine protection contre l'injection SQL si elle est utilisée sur des données brutes.