Il semble que je me heurte souvent à ce problème, car j'ai des données formatées comme ceci:
+----+----------------------+
| id | colors |
+----+----------------------+
| 1 | Red,Green,Blue |
| 2 | Orangered,Periwinkle |
+----+----------------------+
mais je le veux formaté comme ceci:
+----+------------+
| id | colors |
+----+------------+
| 1 | Red |
| 1 | Green |
| 1 | Blue |
| 2 | Orangered |
| 2 | Periwinkle |
+----+------------+
Y at-il un bon moyen de le faire? Comment appelle-t-on ce genre d'opération?
Je pense que c'est ce dont vous avez besoin (procédure stockée): Mysql divise une chaîne de colonne en lignes
DELIMITER $$
DROP PROCEDURE IF EXISTS explode_table $$
CREATE PROCEDURE explode_table(bound VARCHAR(255))
BEGIN
DECLARE id INT DEFAULT 0;
DECLARE value TEXT;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value INT;
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT table1.id, table1.value
FROM table1
WHERE table1.value != '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS table2;
CREATE TEMPORARY TABLE table2(
`id` INT NOT NULL,
`value` VARCHAR(255) NOT NULL
) ENGINE=Memory;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO id, value;
IF done THEN
LEAVE read_loop;
END IF;
SET occurance = (SELECT LENGTH(value)
- LENGTH(REPLACE(value, bound, ''))
+1);
SET i=1;
WHILE i <= occurance DO
SET splitted_value =
(SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(value, bound, i),
LENGTH(SUBSTRING_INDEX(value, bound, i - 1)) + 1), ',', ''));
INSERT INTO table2 VALUES (id, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
SELECT * FROM table2;
CLOSE cur1;
END; $$
Vous pouvez utiliser une requête comme celle-ci:
SELECT
id,
SUBSTRING_INDEX(SUBSTRING_INDEX(colors, ',', n.digit+1), ',', -1) color
FROM
colors
INNER JOIN
(SELECT 0 digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) n
ON LENGTH(REPLACE(colors, ',' , '')) <= LENGTH(colors)-n.digit
ORDER BY
id,
n.digit
S'il vous plaît voir le violon ici . Notez que cette requête prend en charge jusqu'à 4 couleurs pour chaque ligne. Vous devez mettre à jour votre sous-requête pour renvoyer plus de 4 nombres (ou vous devez utiliser un tableau contenant 10 ou 100 nombres).
si le délimiteur fait partie des données mais est entouré de guillemets, comment le scinder?.
Exemple Premier, "deuxième, s", troisième
il devrait venir comme premier deuxième, s troisième
Cela m'a sauvé de nombreuses heures! Pour aller encore plus loin: sur une implémentation typique, il y aurait très probablement un tableau énumérant les couleurs par rapport à une clé d'identification, color_list
. Une nouvelle couleur peut être ajoutée à l'implémentation sans avoir à modifier la requête et la clause union
potentiellement illimitée peut être totalement évitée en remplaçant la requête par ceci:
SELECT id,
SUBSTRING_INDEX(SUBSTRING_INDEX(colors, ',', n.digit+1), ',', -1) color
FROM
colors
INNER JOIN
(select id as digit from color_list) n
ON LENGTH(REPLACE(colors, ',' , '')) <= LENGTH(colors)-n.digit
ORDER BY id, n.digit;
Il est toutefois important que les identifiants de la table color_list restent séquentiels.
remarquez que cela peut être fait sans créer une table temporaire
select id, substring_index(substring_index(genre, ',', n), ',', -1) as genre
from my_table
join
(SELECT @row := @row + 1 as n FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(SELECT @row:=0) r) as numbers
on char_length(genre)
- char_length(replace(genre, ',', '')) >= n - 1