MySQL的枢轴/交叉表查询

问题1:我有一个表格,其结构和数据如下:

app_id transaction_id mobile_no node_id customer_attribute entered_value 100 111 9999999999 1 Q1 2 100 111 9999999999 2 Q2 1 100 111 9999999999 3 Q3 4 100 111 9999999999 4 Q4 3 100 111 9999999999 5 Q5 2 100 222 8888888888 4 Q4 1 100 222 8888888888 3 Q3 2 100 222 8888888888 2 Q2 1 100 222 8888888888 1 Q1 3 100 222 8888888888 5 Q5 4 

我想以下面的格式显示这些logging:

 app_id | transaction_id | mobile | Q1 | Q2 | Q3 | Q4 | Q5 | 100 | 111 | 9999999999 | 2 | 1 | 4 | 3 | 2 | 100 | 222 | 8888888888 | 3 | 1 | 2 | 1 | 4 | 

我知道我需要使用交叉表/数据透视查询来获得这个显示。 为此,我尝试了基于我对此有限的知识。 以下是我的查询:

 SELECT app_id, transaction_id, mobile_no, (CASE node_id WHEN 1 THEN entered_value ELSE '' END) AS user_input1, (CASE node_id WHEN 2 THEN entered_value ELSE '' END) AS user_input2, (CASE node_id WHEN 3 THEN entered_value ELSE '' END) AS user_input3, (CASE node_id WHEN 4 THEN entered_value ELSE '' END) AS user_input4, (CASE node_id WHEN 5 THEN entered_value ELSE '' END) AS user_input5 FROM trn_user_log GROUP BY app_id, transaction_id, mobile_no, node_id 

基于这个查询,我得到了下面的显示:

 app_id transaction_id mobile_no user_input1 user_input2 user_input3 user_input4 user_input5 100 111 9999999999 2 100 111 9999999999 1 100 111 9999999999 4 100 111 9999999999 3 100 111 9999999999 2 100 222 8888888888 3 100 222 8888888888 1 100 222 8888888888 2 100 222 8888888888 1 100 222 8888888888 4 

任何人都可以帮助我正确的更改,我需要作出我的查询获取logging在一个单一的行而不是多行如上。

问题2:还有一种方法可以获取特定字段的值作为列的名称。 正如你所看到的,我有user_input1user_input2 ,…作为头。 而不是我想要customer_attribute的值作为列的标题。

为此我检查了NAME_CONST(name,value)如下:

 SELECT app_id, transaction_id, mobile_no, NAME_CONST(customer_attribute, (CASE node_id WHEN 1 THEN entered_value ELSE '' END)) FROM trn_user_log 

但它给出了一个错误

 Error Code : 1210 Incorrect arguments to NAME_CONST 

需要帮助。

虽然@John的静态答案很好,但是如果你想要转换的列的数量未知,我会考虑使用预处理语句来获得结果:

 SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'GROUP_CONCAT((CASE node_id when ', node_id, ' then entered_value else NULL END)) AS user_input', node_id ) ) INTO @sql FROM trn_user_log; SET @sql = CONCAT('SELECT app_id, transaction_id, mobile_no, ', @sql, ' FROM trn_user_log GROUP BY app_id, transaction_id, mobile_no'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; 

看演示与SQL小提琴

至于你的第二,请澄清你在做什么,这是不明确的。

CASE子句中添加GROUP_CONCAT

 SELECT app_id, transaction_id, mobile_no, GROUP_CONCAT((CASE node_id WHEN 1 THEN entered_value ELSE NULL END)) AS user_input1, GROUP_CONCAT((CASE node_id WHEN 2 THEN entered_value ELSE NULL END)) AS user_input2, GROUP_CONCAT((CASE node_id WHEN 3 THEN entered_value ELSE NULL END)) AS user_input3, GROUP_CONCAT((CASE node_id WHEN 4 THEN entered_value ELSE NULL END)) AS user_input4, GROUP_CONCAT((CASE node_id WHEN 5 THEN entered_value ELSE NULL END)) AS user_input5 FROM trn_user_log GROUP BY app_id, transaction_id, mobile_no 

SQLFiddle演示

@DarkKnightFan,对于我正在工作的任务来说,这是一个非常有帮助的问题。 我继续从@bluefin修改解决scheme来解决你的第二个问题。 以下代码将生成最初请求的格式,其值为customer_attribute的值,作为交叉表中的结果列标题。

相关的变化是要改变的:

 ' then entered_value else NULL END)) AS user_input', node_id 

对此:

 ' then entered_value else NULL END)) AS ''', customer_attribute,'''' 

完整的代码:

 SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'GROUP_CONCAT((CASE node_id when ', node_id, ' then entered_value else NULL END)) AS ''', customer_attribute,'''' ) ) INTO @sql FROM trn_user_log; SET @sql = CONCAT('SELECT app_id, transaction_id, mobile_no, ', @sql, ' FROM trn_user_log GROUP BY app_id, transaction_id, mobile_no'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; 

另外,对于浏览此问题的其他用户,如果您有很多要跨越交叉表的值,则可能会遇到错误,因为GROUP_CONCAT()的默认最大长度为1024个字符。 在你准备好的声明开始时增加这个:

 SET SESSION group_concat_max_len = value; -- replace value with an int