2012-09-12 37 views
6

Pregunta 1: tengo una tabla con la siguiente estructura y los datos:MySQL Query pivote/tabla de referencias cruzadas

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        

quiero mostrar estos registros en el siguiente formato:

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 Sé que necesito usar la consulta de cruce/pivote para obtener esta visualización. Por esto lo probé basándome en el conocimiento limitado que tengo sobre eso. Lo que sigue es mi consulta:

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 

Y en base a esta consulta Tengo el siguiente pantalla:

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    

¿Puede alguien ayudarme con los cambios adecuados que tengo que hacer a mi consulta para obtener los registros en una sola fila y no en varias filas como arriba.

Pregunta 2: También hay una manera de obtener el valor de un campo en particular como el NOMBRE de la columna. Como puede ver arriba, tengo user_input1, user_input2, ... como encabezado. En lugar de eso, quiero tener los valores en customer_attribute como el encabezado de las columnas.

Por esta Revisé NAME_CONST(name,value) de la siguiente manera:

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 

Pero da un error

Error Code : 1210 Incorrect arguments to NAME_CONST 

ayuda requerida.

Respuesta

16

Mientras @ respuesta estática de John funciona muy bien, si usted tiene un número desconocido de columnas que desea transformar, consideraría el uso de declaraciones preparadas para obtener los resultados:

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; 

ver SQL Fiddle with Demo

En cuanto a su segundo, aclare que lo que está tratando de hacer no está claro.

+0

hombre !! lees mi mente ... eso es exactamente lo que quería y estaba haciendo ... Estaba escribiendo un proceso almacenado para hacer exactamente lo mismo. ¡¡¡Muchas gracias!!! – DarkKnightFan

+0

@Gaurav no hay problema, aunque no entiendo completamente tu segunda pregunta. – Taryn

+0

sí, eso es muy complicado ... y dudo que incluso sea posible escribir en un SQL. Quiero que el valor de una columna diga 'customer_attr' para mostrarse como encabezado en lugar de' user_input'. Entonces, por ejemplo, debe aparecer 'Q1' en lugar de' user_input1'. Sé que puedo manejar esto en el código Java obteniendo las columnas del encabezado por separado y mostrándolas de la misma manera. Pero me preguntaba si tal cosa es posible o no. De todas formas, gracias por su ayuda. – DarkKnightFan

7

Añadir GROUP_CONCAT en su cláusula 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 Demo

+0

Lo siento, pero no funcionó! – DarkKnightFan

+0

@Gaurav ¿por qué funcionó en el [SQLFiddle] (http://sqlfiddle.com/#!2/7cbde/4) trabajo? elimine 'node_id' en su grupo mediante la cláusula –

+0

¡Excelente! funcionó ahora. Olvidé eliminar 'node_id' del groupby. ¿Tienes la respuesta a mi segunda pregunta? mostrar el valor de 'customer_attribute' en lugar de' user_inputx'? – DarkKnightFan

1

@DarkKnightFan, esta fue una pregunta muy útil para una tarea en la que estaba trabajando. Seguí adelante y modifiqué la solución de @bluefin para resolver su segunda pregunta. El siguiente código produce el formato solicitado originalmente con el valor de customer_attribute como encabezados de columna resultantes en la tabla cruzada.

El cambio relevante fue cambiar:

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

A esto:

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

El código completo:

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; 

Además, para otros usuarios navegando en este tema, si tiene muchos valores que está intentando cruzar tabula, puede encontrar errores porque GROUP_CONCAT() tiene un valor predeterminado longitud máxima de 1024 caracteres. Para aumentar ponga esto al comienzo de su declaración preparada:

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