Il est vrai que ce n'est pas une bonne idée de dénormaliser en JSON, mais parfois vous devez gérer des données JSON, et il existe un moyen d'extraire un tableau JSON en lignes dans une requête.
L'astuce consiste à effectuer une jointure sur une table d'index temporaire ou en ligne, ce qui vous donne une ligne pour chaque valeur non nulle dans un tableau JSON. C'est-à-dire que si vous avez une table avec les valeurs 0, 1 et 2 que vous joignez à un tableau JSON "fish" avec deux entrées, alors fish[0] correspond à 0, ce qui donne une ligne, et fish1 correspond à 1, ce qui donne une deuxième ligne, mais fish[2] est nul, il ne correspond donc pas à 2 et ne produit pas de ligne dans la jointure. Vous avez besoin d'autant de nombres dans la table d'index que la longueur maximale de n'importe quel tableau dans vos données JSON. C'est un peu un hack, et c'est à peu près aussi douloureux que l'exemple de l'OP, mais c'est très pratique.
Exemple (nécessite MySQL 5.7.8 ou version ultérieure) :
CREATE TABLE t1 (rec_num INT, jdoc JSON);
INSERT INTO t1 VALUES
(1, '{"fish": ["red", "blue"]}'),
(2, '{"fish": ["one", "two", "three"]}');
SELECT
rec_num,
idx,
JSON_EXTRACT(jdoc, CONCAT('$.fish[', idx, ']')) AS fishes
FROM t1
-- Inline table of sequential values to index into JSON array
JOIN (
SELECT 0 AS idx UNION
SELECT 1 AS idx UNION
SELECT 2 AS idx UNION
-- ... continue as needed to max length of JSON array
SELECT 3
) AS indexes
WHERE JSON_EXTRACT(jdoc, CONCAT('$.fish[', idx, ']')) IS NOT NULL
ORDER BY rec_num, idx;
Le résultat est :
+---------+-----+---------+
| rec_num | idx | fishes |
+---------+-----+---------+
| 1 | 0 | "red" |
| 1 | 1 | "blue" |
| 2 | 0 | "one" |
| 2 | 1 | "two" |
| 2 | 2 | "three" |
+---------+-----+---------+
Il semble que l'équipe MySQL puisse ajouter un (L'équipe MySQL a ajouté un JSON_TABLE
fonction dans MySQL 8 pour rendre tout cela plus facile. (http://mysqlserverteam.com/mysql-8-0 -labs-json-aggregation-functions/
)JSON_TABLE
fonction.)