27

I have a legacy table of user information (that is still in active use) and I cannot change the structure of -

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

timezone/language/country etc are only examples of names, they can be variable/there is no finite list other than unique on rows of that column

I need a MySQL compatible SQL query that would return -

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

I've looked through various answers on stackoverflow around hacking Pivot table functionality in to MySQL, and similar but none of them seem to match this case of using variable column name alias from unique row values from a column of the same table. Although I have had little sleep so they're all starting to become a bit of a blur, apologies in advance.

Closest I could find would be to use prepared statements https://stackoverflow.com/a/986088/830171 which would first get all possible/unique values from name column and build a query that uses CASE WHEN, and/or multiple sub-SELECT or JOIN on same table queries.

The alternatives I can think of would be to get all rows for that user id and process them in the application itself in a for-loop, or attempt to limit the names to a finite amount and use sub-SELECTs/JOINs. However that second option is not ideal if a new name is added I'd have to revisit this query.

Please tell me I've missed something obvious

4

1 回答 1

48

与其他一些 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()受变量限制(默认为 1024 字节:除非您有一些非常长的值group_concat_max_len,否则在此处不太可能相关)。name

于 2012-06-07T05:23:28.560 回答