2010-02-12 17 views
16

Tengo datos en una tabla mysql en formato largo/alto (descrito a continuación) y deseo convertirlo a formato ancho. ¿Puedo hacer esto usando solo sql?Mysql, remodele los datos de largo/alto a ancho

Lo más fácil de explicar con un ejemplo. Suponga que tiene información sobre (país, clave, valor) para los países M, N claves (por ejemplo, claves pueden ser los ingresos, líder político, área, continente, etc.)

Long format has 3 columns: country, key, value 
    - M*N rows. 
    e.g. 
    'USA', 'President', 'Obama' 
    ... 
    'USA', 'Currency', 'Dollar' 

Wide format has N=16 columns: county, key1, ..., keyN 
    - M rows 
example: 
    country, President, ... , Currency 
    'USA', 'Obama', ... , 'Dollar' 

¿Hay alguna manera en SQL para crear una nueva tabla con los datos en el formato ancho?

select distinct key from table; 

// esto me conseguirá todas las llaves.

1) ¿Cómo puedo crear la tabla utilizando estos elementos clave?

2) ¿Cómo llego a los valores de la tabla?

Estoy bastante seguro de que puedo hacer esto con cualquier lenguaje de scripting (me gusta Python), pero quería saber si hay una manera fácil de hacerlo en mysql. Muchos paquetes estadísticos como R y STATA tienen este comando incorporado porque se usa con frecuencia.

======

Para ser más claro, aquí está la salida de entrada deseada para un caso sencillo:

de entrada:

country attrName attrValue  key (these are column names) 
US   President Obama   2 
US   Currency Dollar  3 
China  President Hu   4 
China  Currency Yuan   5 

salida

country President Currency newPkey 
US   Obama  Dollar  1 
China  Hu   Yuan  2 

Respuesta

11

tablas de referencias cruzadas o tablas de pivote es la respuesta. Desde allí, puede SELECCIONAR DESDE ... INSERTAR EN ... o crear una VISTA desde el único SELECCIONAR.

Algo así como:

SELECT country, 
     MAX(IF(key='President', value, NULL)) AS President, 
     MAX(IF(key='Currency', value, NULL)) AS Currency, 
     ... 

FROM table 
GROUP BY country; 

Para más información: http://dev.mysql.com/tech-resources/articles/wizard/index.html

+3

Mi forma de trabajar. Tu camino es mucho mejor. TE AMO o gracias. Haga su elección sobre cuál prefiere para expresar su agradecimiento. – chongman

+1

El operador IF es propietario de MySQL. Use CASE en su lugar para cumplir con SQL estándar. Más detalles aquí: [SQLite long to wide formats?] (Http://www.stackoverflow.com/questions/2444708/sqlite-long-to-wide-formats) – SuperAce99

+0

@mluebke: su enlace está muerto :( –

3

Si usaba SQL Server, sería fácil usar UNPIVOT. Hasta donde yo sé, esto no está implementado en MySQL, así que si quieres hacer esto (y te aconsejaría que no lo haga) probablemente tendrás que generar el SQL dinámicamente, y eso es desordenado.

3

Creo que encontré la solución, que usa VIEWS e INSERT INTO (como lo sugiere e4c5).

Tienes que obtener tu lista de AttrNames/Keys, pero MYSQL hace el otro trabajo pesado.

Para el caso de prueba simple anterior, cree la nueva tabla con las columnas adecuadas (no olvide tener también una clave primaria de incremento automático). Entonces

CREATE VIEW a 
AS SELECT country, attrValue 
WHERE attrName="President"; 

CREATE VIEW b 
AS SELECT country, attrValue 
WHERE attrName="Currency"; 


INSERT INTO newtable(country, President, Currency) 
SELECT a.country, a.attrValue, b.attrValue 
FROM a 
INNER JOIN b ON a.country=b.country; 

Si tiene más attrNames, a continuación, crear una vista para cada uno y luego ajustar la última declaración en consecuencia.

INSERT INTO newtable(country, President, Currency, Capital, Population) 
SELECT a.country, a.attrValue, b.attrValue, c.attrValue, d.attrValue 
FROM a 
INNER JOIN b ON a.country=b.country 
INNER JOIN c ON a.country=c.country 
INNER JOIN d ON a.country=d.country; 

Algunos consejos más

  • uso natural combinación izquierda y usted no tiene que especificar la cláusula ON
Cuestiones relacionadas