2010-08-03 8 views
9

Mam coś podobnego do poniższej tabeli:SQL - jak przetransponować?

================================================ 
| 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] | 
------------------------------------------------ 

Potrzebuję kwerendę, która będzie dać mi wynik takiego:

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

Zauważ, że wartości w FieldName nie wyłącznie Użytkownik, Hasło i adres e-mail. Mogą to być dowolne wartości zdefiniowane przez użytkownika.

Czy można to zrobić w SQL?

+0

zobaczyć http://stackoverflow.com/questions/649802/how-to-pivot-a-mysql-entity-attribute-value- Schemat dla podobnego pytania. Czy nie jest możliwe obracanie w aplikacji i pozostawienie zapytania prosto do przodu? Jeśli potrzebujesz N atrybutów, będziesz musiał dynamicznie wygenerować zapytanie. –

Odpowiedz

24

MySQL nie obsługuje składni ANSI PIVOT/UNPIVOT, tak aby pozostawić możliwość korzystania:

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 

Jak widać, oświadczenia CASE muszą być zdefiniowane na wartości. Aby uzyskać taką dynamikę, musisz użyć MySQL's Prepared Statement (dynamic SQL) syntax.

+0

Jaki jest sens "MAX" w tym zapytaniu? – KLee1

+0

@KLee - Więc nie musi grupować według tych kolumn. – dcp

+0

@ KLee1: Ponieważ instrukcja case nie pasuje do zapytania - w różnych miejscach będą wartości null. Więc musisz użyć GROUP BY, aby spłaszczyć zapytanie - MAX przyjmuje najwyższą wartość, a wszystko jest wyższe niż NULL. –

1

Można użyć GROUP_CONCAT

(niesprawdzone)

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

Ryzykowne, ponieważ jeśli część ELSE nie zwróciła wartości NULL, GROUP_CONCAT zwróci listę rozdzielaną przecinkami. –