mysql选择动态行值作为列名,另一列作为值

时间:2012-06-07 03:54:10

标签: mysql sql pivot-table

我有一个用户信息的遗留表(仍处于活动状态)并且我无法更改结构 -

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

我已经查看了有关在数据库中将黑客数据库表功能包含在堆栈中的各种答案,并且类似但是它们似乎都不匹配使用来自同一个表的列中的唯一行值的变量列名别名的情况。虽然我睡得很少,所以他们都开始有点模糊,提前道歉。

最接近我可以找到使用预准备语句https://stackoverflow.com/a/986088/830171,它首先从名称列中获取所有可能/唯一值,并构建使用CASE WHEN和/或多个子查询{{3}}的查询在同一个表查询中使用1}}或SELECT

我能想到的替代方法是获取该用户id的所有行并在for循环中在应用程序本身中处理它们,或尝试将名称限制为有限数量并使用sub - {{1} } S / JOIN秒。但是,如果添加新名称,第二个选项并不理想,我必须重新访问此查询。

请告诉我,我错过了一些明显的东西

1 个答案:

答案 0 :(得分:40)

与其他一些RDBMS不同,MySQL本身不支持此类设计的转换操作(开发人员认为它更适合于应用程序的表示,而不是数据库层)。

如果你绝对必须在MySQL中进行这样的操作,那么构建一个准备好的语句是可行的 - 尽管不是在使用CASE,我可能只是使用MySQL的GROUP_CONCAT()函数:< / p>

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值。)