2010-02-12 8 views
16

J'ai des données dans une table mysql en format long/grand (décrit ci-dessous) et je veux le convertir en format large. Puis-je le faire en utilisant simplement sql?Mysql, remodeler les données de long/grand à large

Plus facile à expliquer avec un exemple. Supposons que vous avez des informations sur (pays, clé, valeur) pour les pays clés M, N (clés peuvent être revenus, leader politique, région, continent, 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' 

Est-il possible dans SQL pour créer une nouvelle table avec les données au format large?

select distinct key from table; 

// cela me donnera toutes les clés.

1) Comment puis-je créer la table en utilisant ces éléments clés?

2) Comment puis-je remplir les valeurs de la table?

Je suis assez sûr que je peux le faire avec n'importe quel langage de script (j'aime python), mais je voulais savoir s'il y avait un moyen facile de le faire dans mysql. De nombreux paquets statistiques comme R et STATA ont cette commande intégrée car elle est souvent utilisée.

======

Pour être plus clair, voici la sortie d'entrée souhaitée pour un cas simple:

Entrée:

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

Sortie

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

Répondre

11

tables croisées onglets ou pivot est la réponse. À partir de là, vous pouvez sélectionner depuis ... insérer dans ... ou créer une vue à partir du seul SELECT.

Quelque chose comme:

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

FROM table 
GROUP BY country; 

Pour plus d'informations: http://dev.mysql.com/tech-resources/articles/wizard/index.html

+3

Mon mode de fonctionnement. Votre chemin est beaucoup mieux. Je t'aime ou merci. Faites votre choix sur celui que vous préférez comme un moyen d'exprimer votre appréciation. – chongman

+1

L'opérateur IF est propriétaire de MySQL. Utilisez plutôt CASE pour être compatible avec SQL standard. Plus de détails ici: [SQLite longs à larges formats?] (Http://www.stackoverflow.com/questions/2444708/sqlite-long-to-wide-formats) – SuperAce99

+0

@mluebke: votre lien est mort :( –

3

Si vous utilisiez SQL Server, ce serait facile en utilisant UNPIVOT. Pour autant que je sache, ceci n'est pas implémenté dans MySQL, donc si vous voulez le faire (et je vous le déconseille), vous devrez probablement générer le SQL dynamiquement, et c'est compliqué.

3

Je pense avoir trouvé la solution, qui utilise VIEWS et INSERT INTO (comme suggéré par e4c5).

Vous devez obtenir votre liste de AttrNames/clés vous-même, mais MYSQL fait l'autre lourde tâche. Pour le cas de test simple ci-dessus, créez la table new_table avec les colonnes appropriées (n'oubliez pas d'avoir également une clé primaire auto-incrémentée). Puis

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 vous avez plus attrNames, puis créer une vue pour chacun, puis ajuster la dernière instruction en conséquence.

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; 

Quelques conseils plus

  • usage naturel LEFT JOIN et vous ne devez pas spécifier la clause ON
Questions connexes