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

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

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

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

Q&A

解決済

1回答

396閲覧

JSON の構造で SELECT したいが、値がないときは不要

origa3

総合スコア22

MySQL

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

0グッド

1クリップ

投稿2023/09/09 12:41

実現したいこと

MySQL 5.7 で、JSON で SELECT したいです。

前提

現状はJSON_ARRAYAGG(JSON_OBJECT())を使い JSON での SELECT を実現していますが、下記 発生している問題 に記載したように、値がないときにまで取得されてしまいます。(問題というか正常な動作なのでしょうけれど。)

取得後に削除すれば済む話ですが、値があるときだけ取得するよう修正できないかと模索しています。

発生している問題

下記 該当のソースコードSELECT を実行すると、T.id がないときにまで tags の連想配列を(全てが null の値で)生成してしまいます。
こうなるのです。

php

1[ 2 'id' => 1, 3 'tags' => [ 4 ['id' => null, 'name' => null] 5 ] 6]

該当のソースコード

こちらが問題の SELECT です。
JSON_ARRAYAGG(JSON_OBJECT())を使い JSON で SELECT しています。

MySQL

1SELECT 2 C.id, 3 4 -- tags 5 JSON_ARRAYAGG(JSON_OBJECT( 6 'id', T.id, 7 'name', T.name 8 )) AS tags 9 10FROM 11 t_comments C 12 LEFT JOIN t_comment_tags CT ON CT.comment_id = C.id 13 LEFT JOIN t_tags T ON T.id = CT.tag_id 14 15WHERE 16 C.supplier_id = 1 17 AND C.item_kind_id = 10 18 19GROUP BY C.id

試したこと

そこでT.idの有無を確認してからJSON_ARRAYAGG(JSON_OBJECT())を使うようCASE~WHENしてみました。こちらです。

SELECT C.id, -- tags CASE WHEN T.id IS NOT NULL THEN JSON_ARRAYAGG(JSON_OBJECT( 'id', T.id, 'name', T.name )) ELSE NULL END AS tags FROM t_comments C LEFT JOIN t_comment_tags CT ON CT.comment_id = C.id LEFT JOIN t_tags T ON T.id = CT.tag_id WHERE C.supplier_id = 1 AND C.item_kind_id = 10 GROUP BY C.id

しかしこちらのエラーになります。

#1055 - Expression #11 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test_database.T.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

もちろん、「only_full_group_byの解除」という解決策は採りたくありません。

あと自力で考えられる解決策はGROUP BY C.idGROUP BY C.id, T.id, T.name と記述することですが、汚いですよね。(実際にはC.id以外にもC.titleC.author_idなど多数のカラムがありそれら全て記述しないといけません。)

補足情報(FW/ツールのバージョンなど)

MySQL 5.7 です。
PHP の PDO で実行します。

もしこういったケースに対する良い解決策がございましたらご指導を賜りますようお願い申し上げます。

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

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

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

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

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

68user

2023/09/09 19:41

C.id で集約したとして、その中に複数の T.idT.name があったらどうするの? というエラーなわけで、group by に全部列挙するか、max などの関数を使うのは自然だと思うんですが違いますかね。というか only_full_group_by なのに最初のコードはエラーにならないんでしょうか (私が何か勘違いをしている?)
origa3

2023/09/11 04:38 編集

68user様、どうなのでしょうか。プログラマー経験が浅く自然さの判定ができないのですが、自然でしたら安心です。 hoshi-takanori様、同じ件ですね。ありがとうございます。英語でもよくググるべきでした。申し訳ございません。
guest

回答1

0

ベストアンサー

T.idの有無を確認してからJSON_ARRAYAGG(JSON_OBJECT())を使うようCASE~WHENして

ここですが、要は「集約値でないT.idを直接使うな」ということなので

sql

1 CASE 2 WHEN sum(case when T.id is NULL then 0 else 1 end) > 0 THEN 3 JSON_ARRAYAGG(JSON_OBJECT( 4 'id', T.id, 5 'name', T.name 6 )) 7 ELSE 8 NULL 9 END AS tags

とかだとうまくいきそうな気がします

投稿2023/09/09 14:24

pecmm

総合スコア760

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

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

origa3

2023/09/11 04:13

お見事な案で、うまくいきました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問