简体   繁体   English

MySQL数据透视/交叉表查询

[英]mysql pivot/crosstab query

Question 1: I have a table with the below structure and data: 问题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                             

I want to display these records in the below format: 我想以以下格式显示这些记录:

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   |

I know I need to use crosstab/pivot query to get this display. 我知道我需要使用交叉表/数据透视查询来获得此显示。 For this I tried it based on the limited knowledge that I have about it. 为此,我基于对它的有限知识对其进行了尝试。 Following is my query: 以下是我的查询:

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

And based on this query I got the below display: 根据此查询,我得到以下显示:

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            

Can anyone help me with the proper changes that I need to make to my query to get the records in one single row and not multiple rows as above. 任何人都可以帮助我对查询进行适当的更改以获取单行而不是如上所述的多行记录。

Question 2: Also is there a way to get the value of a particular field as the NAME of the column. 问题2:还有一种方法可以获取特定字段的值作为列的名称。 As you can see above I have user_input1 , user_input2 ,... as the header. 如您在上面看到的,我有user_input1user_input2 ,...作为标题。 Instead of that I want to have the values in customer_attribute as the header of the columns. 取而代之的是,我希望将customer_attribute的值作为列的标题。

For this I checked NAME_CONST(name,value) as below: 为此,我检查了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 

But it gives an error 但是它给出了一个错误

Error Code : 1210 Incorrect arguments to NAME_CONST

Help required. 需要帮助。

While @John's static answer works great, if you have an unknown number of columns that you want to transform, I would consider using prepared statements to get the results: 虽然@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;

see SQL Fiddle with Demo 参见带有演示的SQL Fiddle

As far as your second, please clarify what you are trying to do it is not clear. 至于您的第二个,请说清楚您要做什么。

Add GROUP_CONCAT in your CASE clause 在您的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 Demo SQLFiddle演示

@DarkKnightFan, this was a very helpful question for a task I was working. @DarkKnightFan,对于我正在执行的任务,这是一个非常有用的问题。 I went ahead and modified the solution from @bluefin to solve your second question. 我继续修改了@bluefin的解决方案,以解决您的第二个问题。 The following code produces your originally requested format with the value of customer_attribute as the resulting column headings in the cross-tab. 以下代码生成您最初请求的格式,其值Customer_attribute作为交叉表中的结果列标题。

The relevant change was to change: 相关的更改是更改:

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

To this: 对此:

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

The full code: 完整代码:

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;

Also, for other users browsing this issue, if you have a lot of values that you are trying to cross-tab, you may run into error because GROUP_CONCAT() has a default max length of 1024 characters. 另外,对于浏览此问题的其他用户,如果您有很多试图交叉制表的值,则可能会出错,因为GROUP_CONCAT()的默认最大长度为1024个字符。 To increase put this at the start of your prepared statement: 为了增加这一点,请将其放在准备好的语句的开头:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM