質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Q&A

解決済

3回答

4125閲覧

MySQL JSON型の検索・変換(valueを置き換えたい)

BlueBits

総合スコア57

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

0グッド

0クリップ

投稿2018/06/09 14:50

編集2018/06/09 17:22

中間テーブルの作成が適切という回答をいただいております。構成自体がJSON型に適切ではありませんでしたのでご注意ください

MySQLのJSON型の扱いについて質問があります。
もしかしたらJSON以前の問題かもしれませんのでご了承ください。

テーブル:groups

idnamejoin_user
1Aグループ["1","2","4"]
2Bグループ["1","3","5"]
3Cグループ["1","4","3"]
4Dグループ["2","4","5"]

テーブル:users

idname
1A’さん
2B’さん
3C’さん
4D’さん
5E’さん

上記の2テーブルを結合して最終的に以下の出力がしたいと考えています。
groups.join_userのJSONをusers.idとしてusers.nameに変換が目的です。

idnamejoin_userjoin_user_name
1Aグループ["1","2","4"]A'さん,B'さん,D'さん
2Bグループ["1","3","5"]A'さん,C'さん,E'さん
3Cグループ["1","4","3"]A'さん,D'さん,C'さん
4Dグループ["2","4","5"]A'さん,D'さん,E'さん

適切な方法があるとともうのですが
現在、手法としてはGROUP_CONCAT、REGEXP CONCATで作成しています。

SELECT G.id,G.name,G.join_user, GROUP_CONCAT(U.name SEPARATOR '、') AS join_user_name FROM `groups` AS G LEFT JOIN `users` AS U ON G.join_user REGEXP CONCAT('"',U.id, '"') GROUP BY G.id;

一応、目的の出力はできているのですが、皆様に適切なSQL文についてご教示いただきたくご質問いたしました。
何卒お願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Kosuke_Shibuya様より調べて頂いた解決方法です。
コメント内にあるので自己解決方法の場を借りて追記いたします。

*Ver 5.7 では動作しないというコメントも頂いております。

SELECT G.*,GROUP_CONCAT(U.name SEPARATOR '、') AS join_user_name FROM `groups` AS G INNER JOIN `users` AS U ON JSON_SEARCH(G.join_user,'one', U.id) IS NOT NULL GROUP BY G.id;

MySQLバージョン(Ver 8.0.11 for Linux on x86_64 (MySQL Community Server - GPL))

投稿2018/06/09 17:26

BlueBits

総合スコア57

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

こんな感じ

sql

1CREATE TABLE `Groups` ( 2 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 3 `name` varchar(32) DEFAULT NULL, 4 PRIMARY KEY (`id`) 5) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4; 6 7CREATE TABLE `Users` ( 8 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 9 `name` varchar(32) DEFAULT NULL, 10 PRIMARY KEY (`id`) 11) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4; 12 13CREATE TABLE `UserGroup` ( 14 `user_id` int(11) unsigned NOT NULL, 15 `group_id` int(11) unsigned NOT NULL, 16 UNIQUE KEY `user_id` (`user_id`,`group_id`), 17 KEY `group_id` (`group_id`), 18 CONSTRAINT `usergroup_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`) ON UPDATE CASCADE, 19 CONSTRAINT `usergroup_ibfk_2` FOREIGN KEY (`group_id`) REFERENCES `Groups` (`id`) ON UPDATE CASCADE 20) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

sql

1SELECT 2 G.id 3 , G.name 4 , group_concat(U.id) AS join_user 5 , group_concat(U.name) AS join_user_name 6FROM `Groups` G 7LEFT JOIN `UserGroup` UG ON G.id = UG.group_id 8LEFT JOIN `Users` U ON UG.user_id = U.id 9GROUP BY G.id 10

JSON型はインデックスが効かないのでJOINするフィールドには向かないと思います。

投稿2018/06/09 15:47

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BlueBits

2018/06/09 16:03

回答ありがとうございます。この構成だと中間テーブル作ったほうがやっぱりいいですよね。 今後、JSON型を使う機会があり試作とおもったのですが使いどころ自体でよろしくなかったようです。 ただ、JSON型の場合、どのようなSQL文になるのか知りたいという状況です。
退会済みユーザー

退会済みユーザー

2018/06/09 16:04

JSON型を使うべきではないので提示のしようがありません。
BlueBits

2018/06/09 16:17

その通りですね。 そもそもこの構成でJSON型というのが的外れですね。 またJSON型を使う機会で問題に当たった時にご質問する形にいたします。
退会済みユーザー

退会済みユーザー

2018/06/09 16:25

MySQLのJSON型って5.7で初めて実装されたものなので、インデックスが効かないとか、十分に関数が用意されていないとか、あまり出番のない方ではないかと思います。実際実運用で使ったことないです。もう少し、枯れてから使うと考えてよいかと思います。
BlueBits

2018/06/09 16:34

その通りですね。今回JSON型をと思ったのもNoSQLを使う要素が出てきそう。 ただNoSQLは入れたくない。そういえばMySQLにJSON型実装された。NoSQLの代用、どんな感じにできるかというのが始点です。 いざ本番でJSON型を使用して???とつまづくよりは別解(中間テーブル)がある中で模索をとおもったのですがあまりにも適切ではなかったですね。
退会済みユーザー

退会済みユーザー

2018/06/09 16:42

JSON_SEARCH という関数があるようなので、以下のクエリで試してみました。 SELECT * FROM `Groups` G INNER JOIN `Users` U ON JSON_SEARCH(G.json_user, 'one', U.id) IS NOT NULL; これ、エラーにならないけど、結果が返っってこない。時期尚早なのでしょうね。
BlueBits

2018/06/09 17:13

JSON_SEARCHについてありがとうございます。結果からお伝えいたしますと望んだ結果を得ることができました。(MySQL Ver 8.0.11) SELECT G.*,GROUP_CONCAT(U.name SEPARATOR '、') AS join_user_name FROM `groups` AS G INNER JOIN `users` AS U ON JSON_SEARCH(G.join_user,'one', U.id) IS NOT NULL GROUP BY G.id; ただ頂いた回答も踏まえますと、堅実に設計したほうがいいですね。 望んだ結果はでてますが、不安しか残りません。 適切な設計ではないのに調べていただきありがとうございました。
退会済みユーザー

退会済みユーザー

2018/06/09 17:15

自分の環境5.7とは動きが異なるようですね〜
BlueBits

2018/06/09 17:19

今回、実験用にVer 8を入れて試していましたが、当分は実用には無理ですね・・・ 遅い時間まで付き合っていただきありがとうございました。 使える、使えないは別として望んだ回答も得られましたので締めさせていただきます。 ありがとうございました。
guest

0

1:Nの関係なので、ユーザーテーブルにグループID列を定義するのが、RDBのテーブル設計としてのベストプラクティスです。

投稿2018/06/09 15:22

sagami1991

総合スコア216

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sagami1991

2018/06/09 15:24

間違えました。N:Nなのですね。 だとしたら中間テーブルを作るのが普通だと思います。
sagami1991

2018/06/09 15:34

この設計方法だと、例えばAさんの所属グループを調べたいときに、グループテーブルを全行問い合わせることになります。 N:Nのときは中間テーブル(グループID列, ユーザーID列)を作成するのがRDB設計としてのベストプラクティスです。
BlueBits

2018/06/09 15:50

回答ありがとうございます。ご教示頂いた通り、この構成だと中間テーブルが適切なのだと思います。 JSON型といってもただ配列を入れてるようなものですし・・・ 今回、今後JSON型を使う機会があり試作の段階で当たった課題という形です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問