2010-08-03 11 views
9

J'ai quelque chose de similaire au tableau suivant:SQL - Comment transposer?

================================================ 
| Id | UserId | FieldName  | FieldValue  | 
=====+========+===============+================| 
| 1 | 100 | Username  | John Doe  | 
|----+--------+---------------+----------------| 
| 2 | 100 | Password  | pass123!  | 
|----+--------+---------------+----------------| 
| 3 | 102 | Username  | Jane   | 
|----+--------+---------------+----------------| 
| 4 | 102 | Password  | $ecret   | 
|----+--------+---------------+----------------| 
| 5 | 102 | Email Address | [email protected] | 
------------------------------------------------ 

je besoin d'une requête qui me donnera un résultat comme celui-ci:

================================================== 
| UserId | Username | Password | Email Address | 
=========+===========+===========================| 
| 100 | John Doe | pass123! |    | 
|--------+-----------+----------+----------------| 
| 102 | Jane  | $ecret | [email protected] | 
|--------+-----------+----------+----------------| 

Notez que les valeurs FieldName ne sont pas limitées à Nom d'utilisateur, Mot de passe et adresse e-mail Ils peuvent être n'importe quoi car ils sont définis par l'utilisateur.

Existe-t-il un moyen de le faire en SQL?

+0

voir http://stackoverflow.com/questions/649802/how-to-pivot-a-mysql-entity-attribute-value- schéma pour une question similaire. Est-il impossible de faire le pivotement dans l'application et laisser la requête tout droit? Si vous avez besoin de N attributs, vous devrez générer la requête dynamiquement. –

Répondre

24

MySQL ne supporte pas la norme ANSI PIVOT/syntaxe UNPIVOT, de sorte que vous laisser utiliser:

SELECT t.userid 
     MAX(CASE WHEN t.fieldname = 'Username' THEN t.fieldvalue ELSE NULL END) AS Username, 
     MAX(CASE WHEN t.fieldname = 'Password' THEN t.fieldvalue ELSE NULL END) AS Password, 
     MAX(CASE WHEN t.fieldname = 'Email Address' THEN t.fieldvalue ELSE NULL END) AS Email 
    FROM TABLE t 
GROUP BY t.userid 

Comme vous pouvez le voir, les instructions CASE doivent être définis par valeur. Pour rendre cette dynamique, vous devez utiliser MySQL's Prepared Statement (dynamic SQL) syntax.

+0

Quel est le point de 'MAX' dans cette requête? – KLee1

+0

@KLee - Il n'a donc pas à regrouper par ces colonnes – dcp

+0

@ KLee1: Parce que l'instruction case ne flatte pas la requête - il y aura des zéros à divers endroits. Vous devez donc utiliser GROUP BY pour aplatir la requête - MAX prend la valeur la plus élevée et tout est supérieur à NULL. –

1

Vous pouvez utiliser GROUP_CONCAT

(non testé)

SELECT UserId, 
GROUP_CONCAT(if(fieldname = 'Username', fieldvalue, NULL)) AS 'Username', 
GROUP_CONCAT(if(fieldname = 'Password', fieldvalue, NULL)) AS 'Password', 
GROUP_CONCAT(if(fieldname = 'Email Address', fieldvalue, NULL)) AS 'Email Address', 
FROM table 
GROUP BY UserId 
+1

Risqué, car si la partie ELSE n'a pas renvoyé la valeur NULL, GROUP_CONCAT renvoie une liste délimitée par des virgules. –