web-dev-qa-db-ja.com

mysqlは動的な行の値を列名として選択し、別の列を値として選択します

ユーザー情報のレガシテーブル(まだアクティブに使用中)があり、構造を変更できません-

id    name       value
------------------------------
0     timezone   Europe/London
0     language   en
0     country    45
0     something  x
1     timezone   Europe/Paris
1     language   fr
1     country    46

タイムゾーン/言語/国などは名前の例に過ぎず、変数にすることができます/その列の行に一意以外の有限リストはありません

返されるMySQL互換のSQLクエリが必要です-

id    timezone       language    country  something
---------------------------------------------------
0     Europe/London  en          45       x
1     Europe/Paris   fr          46

Pivotテーブルの機能をMySQLにハッキングすることに関するスタックオーバーフローに関するさまざまな回答を調べましたが、同じテーブルの列の一意の行値から変数列名エイリアスを使用するこのケースに一致するものはありません。私はほとんど眠っていなかったので、それらはすべて少しあいまいになり始めています、事前に謝罪します。

私が見つけることができる最も近いものは、準備されたステートメントを使用することです https://stackoverflow.com/a/986088/830171 これは最初に名前列からすべての可能な/一意の値を取得し、CASE WHENを使用するクエリを構築しますおよび/または同じテーブルクエリの複数のサブ_SELECTまたはJOIN

私が考える代替案は、そのユーザーIDのすべての行を取得してforループ内のアプリケーション自体で処理するか、名前を有限量に制限してsub SELECTs /を使用しようとすることですJOINs。ただし、この2番目のオプションは、新しい名前を追加する場合には理想的ではありません。このクエリを再検討する必要があります。

明らかなものを見逃したことを教えてください

23
gingerCodeNinja

他のいくつかのRDBMSとは異なり、MySQLは設計によるこの種のピボット操作をネイティブにサポートしていません(開発者は、プレゼンテーションよりもプレゼンテーションに適していると感じていますデータベース、アプリケーションのレイヤー)。

MySQL内でこのような操作を絶対に実行する必要がある場合は、準備されたステートメントを作成する方法があります。CASEをいじるのではなく、おそらくMySQLの GROUP_CONCAT() 関数:

SELECT CONCAT(
  'SELECT `table`.id', GROUP_CONCAT('
     ,    `t_', REPLACE(name, '`', '``'), '`.value
         AS `', REPLACE(name, '`', '``'), '`'
     SEPARATOR ''),
 ' FROM `table` ', GROUP_CONCAT('
     LEFT JOIN `table`   AS `t_', REPLACE(name, '`', '``'), '`
            ON `table`.id = `t_', REPLACE(name, '`', '``'), '`.id
           AND `t_', REPLACE(name, '`', '``'), '`.name = ', QUOTE(name)
     SEPARATOR ''),
 ' GROUP BY `table`.id'
) INTO @qry FROM (SELECT DISTINCT name FROM `table`) t;

PREPARE stmt FROM @qry;
EXECUTE stmt;

sqlfiddle でご覧ください。

GROUP_CONCAT() の結果は group_concat_max_len 変数によって制限されることに注意してください(デフォルトの1024バイト:いくつかの場合を除いて、ここでは関係ありません)非常に長いname値)。

40
eggyal