web-dev-qa-db-fra.com

Ligne séparée par des virgules fractionnées SQL

J'ai une colonne avec un nombre variable de valeurs séparées par des virgules:

somethingA,somethingB,somethingC
somethingElseA, somethingElseB

Et je veux que le résultat prenne chaque valeur et crée une ligne:

somethingA
somethingB
somethingC
somethingElseA
somethingElseB

Comment puis-je faire cela en SQL (MySQL)?

(J'ai essayé de googler "imploser" et "vue latérale", mais cela ne semble pas poser de questions connexes. Toutes les questions connexes SO essaient de faire des choses beaucoup plus compliquées)

20
Don P

Vous pouvez le faire avec du SQL pur comme celui-ci

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.values, ',', n.n), ',', -1) value
  FROM table1 t CROSS JOIN 
(
   SELECT a.N + b.N * 10 + 1 n
     FROM 
    (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
   ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
    ORDER BY n
) n
 WHERE n.n <= 1 + (LENGTH(t.values) - LENGTH(REPLACE(t.values, ',', '')))
 ORDER BY value

Remarque: L'astuce consiste à utiliser la table de pointage (nombres) et une fonction MySQL très pratique dans ce cas SUBSTRING_INDEX() . Si vous effectuez un grand nombre de ces requêtes (fractionnement), vous pouvez envisager de remplir et d'utiliser une table de pointage persistante au lieu de la générer à la volée avec une sous-requête comme dans cet exemple. La sous-requête de cet exemple génère une séquence de nombres de 1 à 100, ce qui vous permet de fractionner jusqu'à 100 valeurs délimitées par ligne dans la table source. Si vous avez besoin de plus ou moins, vous pouvez facilement l'ajuster.

Production:

 | VALEUR | 
 | ------------- | quelque choseA | 
 | quelque choseB | 
 | quelque choseC | 
 | somethingElseA | 
 | somethingElseB | 

Voici --- (SQLFiddle démo


Voici à quoi pourrait ressembler la requête avec une table de pointage persistante

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(t.values, ',', n.n), ',', -1) value
  FROM table1 t CROSS JOIN tally n
 WHERE n.n <= 1 + (LENGTH(t.values) - LENGTH(REPLACE(t.values, ',', '')))
 ORDER BY value

Voici SQLFiddle démo

64
peterm