Mysql
 sql >> Base de données >  >> RDS >> Mysql

Valeurs séparées par des virgules dans la clause MySQL IN

En vous basant sur l'exemple FIND_IN_SET() de @Jeremy Smith, vous pouvez le faire avec une jointure pour ne pas avoir à exécuter de sous-requête.

SELECT * FROM table t
JOIN locations l ON FIND_IN_SET(t.e_ID, l.city) > 0
WHERE l.e_ID = ?

Ceci est connu pour fonctionner très mal, car il doit faire des balayages de table, évaluant la fonction FIND_IN_SET() pour chaque combinaison de lignes dans table et locations . Il ne peut pas utiliser d'index et il n'y a aucun moyen de l'améliorer.

Je sais que vous avez dit que vous essayez de tirer le meilleur parti d'une mauvaise conception de base de données, mais vous devez comprendre à quel point c'est radicalement mauvais.

Explication :Supposons que je vous demande de rechercher dans un annuaire téléphonique toutes les personnes dont la première, deuxième ou dernière initiale est "J". Dans ce cas, l'ordre trié du livre ne sert à rien, puisque vous devez de toute façon numériser chaque page.

Le LIKE La solution donnée par @fthiella a un problème similaire en ce qui concerne les performances. Il ne peut pas être indexé.

Voir aussi ma réponse à Le stockage d'une liste délimitée dans une colonne de base de données est-il vraiment si mauvais ? pour les autres pièges de cette façon de stocker des données dénormalisées.

Si vous pouvez créer une table supplémentaire pour stocker un index, vous pouvez associer les emplacements à chaque entrée de la liste des villes :

CREATE TABLE location2city (
 location INT,
 city INT,
 PRIMARY KEY (location, city)
); 

En supposant que vous ayez une table de recherche pour toutes les villes possibles (pas seulement celles mentionnées dans le table ) vous pouvez supporter l'inefficacité une fois pour produire le mapping :

INSERT INTO location2city (location, city)
  SELECT l.e_ID, c.e_ID FROM cities c JOIN locations l
  ON FIND_IN_SET(c.e_ID, l.city) > 0;

Vous pouvez maintenant exécuter une requête beaucoup plus efficace pour trouver des entrées dans votre table :

SELECT * FROM location2city l
JOIN table t ON t.e_ID = l.city
WHERE l.e_ID = ?;

Cela peut faire usage d'un index. Maintenant, il vous suffit de veiller à ce que toute INSERT/UPDATE/DELETE de lignes dans les locations insère également les lignes de mappage correspondantes dans location2city .