web-dev-qa-db-fra.com

Liste de paramètres de clause IN vide dans MySQL

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?

54
Wiz

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.

48
Barmar

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.

12
Asad Saeeduddin

Cela me donne également 0 résultats:

SELECT id FROM User
WHERE id IN (NULL);

Testé sur MYSQL 5.6

8
Pavel Shkleinik

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
}
4
Manic Depression

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') 
3
Jus12

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.

1
Arth