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?
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
FIND_IN_SET est votre ami dans ce cas
select * from shirts where FIND_IN_SET(1,colors)
Examinez la fonction FIND_IN_SET pour MySQL.
SELECT *
FROM shirts
WHERE FIND_IN_SET('1',colors) > 0
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 !!!
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
).
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'
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
select * from shirts where find_in_set('1',colors) <> 0
Travaille pour moi
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.