27

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

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

MySQLへのピボットテーブル機能のハッキングに関するstackoverflowに関するさまざまな回答を調べましたが、同じテーブルの列の一意の行値から変数列名エイリアスを使用する場合と一致するものはないようです。私はほとんど睡眠をとっていなかったので、それらはすべて少しぼやけ始めていますが、事前にお詫び申し上げます。

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

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

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

4

1 に答える 1

48

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

MySQL内でそのような操作を絶対に実行する必要がある場合は、プリペアドステートメントを作成するのが最善の方法です。ただし、をいじくり回すのではなく、CASEMySQLの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()の結果は変数によって制限されることに注意してください(デフォルトは1024バイトです。非常に長い値group_concat_max_lenがない限り、ここでは関係ありません)。name

于 2012-06-07T05:23:28.560 に答える