Вопрос: mysql pivot / crosstab query


Вопрос 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                             

Я хочу отобразить эти записи в следующем формате:

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            

Может ли кто-нибудь помочь мне с надлежащими изменениями, которые мне нужно внести в мой запрос, чтобы получить записи в одной строке, а не в нескольких строках, как указано выше.

Вопрос 2:  Также есть способ получить значение определенного поля как ИМЯ столбца. Как вы можете видеть выше, я user_input1, user_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

Требуется помощь.


7


источник


Ответы:


Хотя статический ответ @ 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 Fiddle с демоверсией

Что касается вашего второго, прошу прояснить, что вы пытаетесь сделать, это неясно.


16



Добавить GROUP_CONCAT в вашей CASE пункт

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


7



@DarkKnightFan, это был очень полезный вопрос для задачи, над которой я работал. Я пошел дальше и изменил решение от @bluefin, чтобы решить ваш второй вопрос. Следующий код создает ваш первоначально запрошенный формат со значением 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

1