🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
MySQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

2回答

6708閲覧

mySQLのテーブルの縦横変換(横→縦)において、キーの数が多い場合の対応

MagMag

総合スコア80

MySQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2020/12/17 01:31

編集2020/12/17 02:05

以下の図のように、縦持ちテーブルを横持ちテーブルに変換したいと思っています(テーブルやスクリプトは以下リンクから引用させていただいています)。

SQL で縦横変換まとめ(pivot と unpivot)

対応方法としてこのページにあるCASE WHENを使って変換する方法はイメージがつくのですが、自分の場合、このキーが100個くらいあります(c1〜c100)。力技で100行のクエリーを書けなくはないのですが、キーが増える度にクエリも書き換えなければならず、不便だと感じています。

Pythonで対応する方法もありますが、これをmySQLで実装する方法はありますでしょうか?
そもそもテーブルの持ち方を変えた方がいいんじゃない?といった指摘でも助かります。

縦持ちテーブル

uidkeyvalue
101c111
101c212
101c313
102c121
102c222
102c323

横持ちテーブル

uidc1c2c3
101111213
102212223

SQL

1SELECT uid, 2 max(CASE WHEN key = 'c1' THEN value END) AS c1, 3 max(CASE WHEN key = 'c2' THEN value END) AS c2, 4 max(CASE WHEN key = 'c3' THEN value END) AS c3 5FROM vtable 6GROUP BY uid 7;

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

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

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

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

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

yambejp

2020/12/17 01:40 編集

uidとkeyの組み合わせはユニークだという担保はありますか? それとテーブルのサンプルは画像の他にテキストでもつけてください
MagMag

2020/12/17 02:53 編集

ありがとうございます。(uid,key)はユニークです。イメージとして、uidが料理名、keyが材料名、valueが使用量です。テキスト化も実施しました。ちなみに、図でも意図が伝わると思ったので、図で掲載としたのですが、テキストで表示することの、回答される方に対するメリットってどこにあるのでしょうか?
guest

回答2

0

キーが増える度にクエリも書き換えなければならず、不便だと感じています。

取得側で列を展開する必要がありますが、以下の様にするとSQLは変更が不要です。

SQL

1select uid 2 , group_concat(key order by key) key_list 3 , group_concat(max_value order by key) value_list 4from ( 5 SELECT uid, key, max(value) max_value 6 FROM vtable 7 GROUP BY uid, key 8) t 9group by uid

解説:key_list のkeyの並びとvalue_listの並びが一致するようになっています。
※文字列への変換は考慮していませんので、必要に応じて適宜変更して下さい。

投稿2020/12/17 02:24

編集2020/12/17 02:26
sazi

総合スコア25327

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

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

MagMag

2020/12/21 07:31

ありがとうございます!
guest

0

ベストアンサー

定形文をプロシージャで処理すればよいでしょう
列順の指定などこまかい仕様を決める必要はありそうですけど。
また表示するのが数値で確定ですか?文字列と数値だと若干処理がかわります

投稿2020/12/17 01:38

yambejp

総合スコア116661

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

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

MagMag

2020/12/17 02:07

ありがとうございます。実データの場合、uidもkeyもテキストですが、uidのINTへの変換は性質上可能です。
yambejp

2020/12/17 04:05 編集

ちなみにkeyというカラム名は予約語と競合するのでおすすめしません 仮にkとしついでにvalueをvとしておきます create table vtable(uid int,k varchar(10),v int,unique(uid,k)); insert into vtable values (101,'c1',11), (101,'c2',12), (101,'c3',13), (102,'c1',21), (102,'c2',22), (102,'c3',23);
yambejp

2020/12/17 04:03 編集

これをさらっとかくとこう select uid ,sum((c1=k)*v) as c1 ,sum((c2=k)*v) as c2 ,sum((c3=k)*v) as c3 from vtable ,(select 'c1','c2','c3') as sub group by uid この流れをプロシージャにするとよいです
yambejp

2020/12/17 04:03 編集

drop procedure if exists proc; delimiter // create procedure proc() begin declare c varchar(10); declare done int default 0; declare cur cursor for select distinct k from vtable order by k; declare continue handler for sqlstate '02000' set done=1; set @sql1:="select uid"; set @sql2:=""; open cur; repeat fetch cur into c; if not done then set @sql1:=concat(@sql1,',sum((`',c,'`=k)*v) as `',c,'`'); set @sql2:=concat(@sql2,case @sql2 when '' then 'select ' else ',' end, '"',c,'"'); end if; until done end repeat; close cur; set @sql1:=concat(@sql1,'from vtable,(',@sql2,') as sub group by uid'); prepare stmt from @sql1; execute stmt; end;
yambejp

2020/12/17 04:07 編集

//実行 call proc(); ※微調整をいくつかいれました あとはvtableのデータを色々いじって試してみてください
MagMag

2020/12/21 07:33

ありがとうございます。プロシージャを勉強しながら実装していきたいと思います。アプリケーション側での対応不要というもともとの目的に照らし、yambejpさんをベストアンサーとさせてください。
sazi

2020/12/21 08:13 編集

> アプリケーション側での対応不要 カラムが動的に変化しても、アプリケーション側の変更はは不要なんですね。 テーブルのレイアウト変えるのも問題ないって事ですか。
MagMag

2020/12/21 09:12 編集

この例ではアプリケーション側で機械学習に一括でかけるので、カラムが増えても追加処理は不要です。 一方、データ抽出においてはこのデータだけでなく、他の条件で抽出したデータとjoinしないといけないため、抽出はSQLだけで済ませたいと思っていました。イメージが伝わりきらず申し訳ありません。 saziさんの方法もシンプルで大変わかりやすいので、ベストアンサーに選ぼうか迷ったのですが、、。
sazi

2020/12/21 12:06

問題ないなら、スルーしてOKです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問