Mon objectif est de savoir comment obtenir une relation entre une colonne qui a des références dans un tableau json à une autre. De manière simplifiée, j'ai deux tableaux:
select version(); CREATE TABLE `table_a` ( `id` int(11) NOT NULL, `references` json NULL ); CREATE TABLE `table_b` ( `id` int(11) NOT NULL, `name` text NULL ); INSERT INTO `table_a` (`id`, `references`) VALUES (1, '\"[1,3]\"'), (2, '\"[2,3]\"'); INSERT INTO `table_b` (`id`, `name`) VALUES (1, 'item_1'), (2, 'item_2'), (3, 'item_3'); SELECT * from table_a; SELECT * from table_b; select `references` from table_a where id=1; SELECT JSON_SEARCH((select `references` from table_a where id=1), 'one', '3');
Dont les références sont un tableau json d'entiers et la table b
|-----|----------| | 1 | "item 1" | | 3 | "item 3" |
Donc, je voudrais obtenir tous les éléments de la table B liés à un élément de la table A avec l'identifiant, par exemple, 1 qui ont leurs identifiants dans la colonne références tableau entier (comme json).
Quelque chose comme ça:
table_b | id | name | |-----|----------| | 1 | "item 1" | | 2 | "item 2" | | 3 | "item 3" |
J'ai essayé d'y parvenir avec json_contains , json_extract , json_search , etc. de la documentation et je pense que ce problème est de faire correspondre les valeurs à l'intérieur du tableau d'entiers json.
Par exemple:
SELECT JSON_SEARCH((select references from table_a where id=1), 'one', '3');
doit retourner quelque chose mais toujours retourner NULL
et je ne comprends pas bien. J'ai aussi essayé avec 3
sans guillemets.
Une idée?
Ma version actuelle de MySQL est la 5.7.25
Merci d'avance.
Code minimal à reproduire:
table_a | id | references | |-----|------------| | 1 | "[1,3]" | | 2 | "[2,3]" |
Sandbox à tester: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=ac557666852fa94e77fdf87158c9abe0
3 Réponses :
JSON incorrect (mais vérifié avec succès par la fonction JSON_VALID).
La solution est monstrueuse:
SELECT table_b.* FROM table_a, table_b WHERE table_a.id = 1 AND JSON_SEARCH(REPLACE(REPLACE(REPLACE(REPLACE(table_a.references, '"', ''), '[', '["'), ']', '"]'), ',', '","'), 'one', table_b.id) IS NOT NULL
tripoter quelques requêtes supplémentaires qui expliquent le problème.
Vous pouvez utiliser la requête suivante comme solution:
select table_a.*, table_b.* from table_a join table_b on JSON_CONTAINS( CAST(TRIM('"' FROM `references`) as JSON), CAST(table_b.id as JSON) ) where table_a.id=2;
Étant donné que votre champ de references
n'est pas de type JSON valide, vous devez le convertir en JSON et après cela, les fonctions JSON_CONTAINS peuvent être utilisées.
Essayez-le ici
Vous pouvez d'abord vous débarrasser des guillemets enveloppant le tableau, puis concaténer les entiers résultants avec des sous-chaînes item_
avec l'utilisation de sous-requêtes auxiliaires dont l'une génère des lignes afin d'obtenir consécutivement chaque membre du tableau tel que
SELECT b.* FROM ( SELECT @i := @i + 1 AS rn, CONCAT('item_',JSON_EXTRACT(JSON_UNQUOTE(`references`), CONCAT('$[',@i-1,']'))) AS name FROM information_schema.tables CROSS JOIN `table_a` AS a CROSS JOIN (SELECT @i := 0) r WHERE @i < JSON_LENGTH(JSON_UNQUOTE(`references`)) ) AS a JOIN `table_b` AS b ON b.`name` = a.name
Afficher les données source sous forme de scripts CREATE TABLE + INSERT INTO (ou créer un violon en ligne). Afficher la sortie souhaitée sous forme de tableau textuel formaté.
Pourquoi utilisez-vous un tableau JSON au lieu d'un schéma normal normalisé?
@Akina je l'ai mis à jour.
@ Fraise je le sais. Mais c'est l'exigence du modèle de données en ce moment. Si je ne peux pas y parvenir, je vais le refactoriser.
Je ne vois pas le résultat souhaité ..
@Akina Merci pour votre aide. J'ai mis à jour à nouveau. Pardon :)
À la fin. J'ai changé de modèle car cela pose beaucoup de problèmes. Je ne me souviens jamais du principe KISS. Merci à tous pour votre aide.