web-dev-qa-db-fra.com

Requête MySQL recherchant des valeurs dans une chaîne séparée par des virgules

J'ai un champ COLORS (varchar(50)) dans une table SHIRTS qui contient une chaîne délimitée par des virgules telle que 1,2,5,12,15,. Chaque nombre représentant les couleurs disponibles.

Lors de l'exécution de la requête select * from shirts where colors like '%1%' pour obtenir tous les chemises rouges (couleur = 1), j'obtiens également les chemises dont la couleur est gris (= 12) et orange (= 15). 

Comment dois-je réécrire la requête pour qu'elle sélectionne SEULEMENT la couleur 1 et non toutes les couleurs contenant le chiffre 1?

69
bikey77

La méthode classique consiste à ajouter des virgules à gauche et à droite:

select * from shirts where CONCAT(',', colors, ',') like '%,1,%'

Mais find_in_set fonctionne aussi:

select * from shirts where find_in_set('1',colors) <> 0
154
Andomar

FIND_IN_SET est votre ami dans ce cas

select * from shirts where FIND_IN_SET(1,colors) 
26
Shakti Singh

Examinez la fonction FIND_IN_SET pour MySQL.

SELECT * 
    FROM shirts 
    WHERE FIND_IN_SET('1',colors) > 0
21
Joe Stefanelli

Cela fonctionnera à coup sûr, et j'ai effectivement essayé:

lwdba@localhost (DB test) :: DROP TABLE IF EXISTS shirts;
Query OK, 0 rows affected (0.08 sec)

lwdba@localhost (DB test) :: CREATE TABLE shirts
    -> (<BR>
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> ticketnumber INT,
    -> colors VARCHAR(30)
    -> );<BR>
Query OK, 0 rows affected (0.19 sec)

lwdba@localhost (DB test) :: INSERT INTO shirts (ticketnumber,colors) VALUES
    -> (32423,'1,2,5,12,15'),
    -> (32424,'1,5,12,15,30'),
    -> (32425,'2,5,11,15,28'),
    -> (32426,'1,2,7,12,15'),
    -> (32427,'2,4,8,12,15');
Query OK, 5 rows affected (0.06 sec)
Records: 5  Duplicates: 0  Warnings: 0

lwdba@localhost (DB test) :: SELECT * FROM shirts WHERE LOCATE(CONCAT(',', 1 ,','),CONCAT(',',colors,',')) > 0;
+----+--------------+--------------+
| id | ticketnumber | colors       |
+----+--------------+--------------+
|  1 |        32423 | 1,2,5,12,15  |
|  2 |        32424 | 1,5,12,15,30 |
|  4 |        32426 | 1,2,7,12,15  |
+----+--------------+--------------+
3 rows in set (0.00 sec)

Essaie !!!

10
RolandoMySQLDBA

Si le jeu de couleurs est plus ou moins fixe, le moyen le plus efficace et le plus lisible serait d'utiliser des constantes de chaîne dans votre application, puis d'utiliser le type SET de MySQL avec FIND_IN_SET('red',colors) dans vos requêtes. Lorsque vous utilisez le type SET avec FIND_IN_SET , MySQL utilise un entier pour stocker toutes les valeurs et utilise l'opération "and" binaire pour vérifier la présence de valeurs, ce qui est beaucoup plus efficace que d'analyser une chaîne séparée par des virgules.

Dans SET('red','blue','green'), 'red' serait stocké en interne en tant que 1, 'blue' serait stocké en interne en tant que 2 et 'green' serait stocké en interne en tant que 4. La valeur 'red,blue' serait stockée sous la forme 3 (1|2) et 'red,green' sous la forme 5 (1|4).

6
ColinM

Si vous utilisez MySQL, il existe une méthode REGEXP que vous pouvez utiliser ...

http://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp

Alors vous utiliseriez:

SELECT * FROM `shirts` WHERE `colors` REGEXP '\b1\b'
3
KOGI

En fait, vous devriez corriger votre schéma de base de données de manière à avoir trois tables:

shirt: shirt_id, shirt_name
color: color_id, color_name
shirtcolor: shirt_id, color_id

Ensuite, si vous voulez trouver tous les chemises qui sont rouges, vous ferez une requête comme celle-ci:

SELECT *
FROM shirt, color
WHERE color.color_name = 'red'
  AND shirt.shirt_id = shirtcolor.shirt_id
  AND color.color_id = shirtcolor.color_id
3
CanSpice
select * from shirts where find_in_set('1',colors) <> 0

Travaille pour moi

0
Deepak Bhatta

Vous pouvez y parvenir en suivant la fonction.

Exécuter la requête suivante pour créer une fonction.

DELIMITER ||
CREATE FUNCTION `TOTAL_OCCURANCE`(`commastring` TEXT, `findme`     VARCHAR(255)) RETURNS int(11)
NO SQL
-- SANI: First param is for comma separated string and 2nd for string to find.
return ROUND (   
    (
        LENGTH(commastring)
        - LENGTH( REPLACE ( commastring, findme, "") ) 
    ) / LENGTH(findme)        
);

Et appelez cette fonction comme ça

msyql> select TOTAL_OCCURANCE('A,B,C,A,D,X,B,AB', 'A');

J'espère que ça aiderait.

0
Delickate