sql >> Databasteknik >  >> RDS >> Mysql

MySQL - Rader till kolumner

Jag kommer att lägga till en något längre och mer detaljerad förklaring av stegen för att lösa detta problem. Jag ber om ursäkt om det är för långt.

Jag börjar med basen du har gett och använder den för att definiera ett par termer som jag kommer att använda för resten av det här inlägget. Detta kommer att vara bastabellen :

select * from history;

+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
|      1 | A        |        10 |
|      1 | B        |         3 |
|      2 | A        |         9 |
|      2 | C        |        40 |
+--------+----------+-----------+

Detta kommer att vara vårt mål, den sköna pivottabellen :

select * from history_itemvalue_pivot;

+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 |    0 |
|      2 |    9 |    0 |   40 |
+--------+------+------+------+

Värden i history.hostid kolumnen blir y-värden i pivottabellen. Värden i history.itemname kolumnen blir x-värden (av uppenbara skäl).

När jag måste lösa problemet med att skapa en pivottabell, tar jag itu med det med en trestegsprocess (med ett valfritt fjärde steg):

  1. välj kolumnerna av intresse, dvs. y-värden och x-värden
  2. utöka bastabellen med extra kolumner -- en för varje x-värde
  3. gruppera och aggregera den utökade tabellen -- en grupp för varje y-värde
  4. (valfritt) förfina den aggregerade tabellen

Låt oss tillämpa dessa steg på ditt problem och se vad vi får:

Steg 1:välj kolumner av intresse . I önskat resultat, hostid ger y-värdena och itemname tillhandahåller x-värden .

Steg 2:utöka bastabellen med extra kolumner . Vi behöver vanligtvis en kolumn per x-värde. Kom ihåg att vår x-värdeskolumn är itemname :

create view history_extended as (
  select
    history.*,
    case when itemname = "A" then itemvalue end as A,
    case when itemname = "B" then itemvalue end as B,
    case when itemname = "C" then itemvalue end as C
  from history
);

select * from history_extended;

+--------+----------+-----------+------+------+------+
| hostid | itemname | itemvalue | A    | B    | C    |
+--------+----------+-----------+------+------+------+
|      1 | A        |        10 |   10 | NULL | NULL |
|      1 | B        |         3 | NULL |    3 | NULL |
|      2 | A        |         9 |    9 | NULL | NULL |
|      2 | C        |        40 | NULL | NULL |   40 |
+--------+----------+-----------+------+------+------+

Observera att vi inte ändrade antalet rader – vi lade bara till extra kolumner. Notera också mönstret för NULL s -- en rad med itemname = "A" har ett icke-nullvärde för ny kolumn A , och null-värden för de andra nya kolumnerna.

Steg 3:gruppera och aggregera den utökade tabellen . Vi måste group by hostid eftersom det ger y-värdena:

create view history_itemvalue_pivot as (
  select
    hostid,
    sum(A) as A,
    sum(B) as B,
    sum(C) as C
  from history_extended
  group by hostid
);

select * from history_itemvalue_pivot;

+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 | NULL |
|      2 |    9 | NULL |   40 |
+--------+------+------+------+

(Observera att vi nu har en rad per y-värde.) Okej, vi är nästan framme! Vi behöver bara bli av med de där fula NULL s.

Steg 4:försköna . Vi kommer bara att ersätta alla nollvärden med nollor så att resultatuppsättningen är snyggare att titta på:

create view history_itemvalue_pivot_pretty as (
  select 
    hostid, 
    coalesce(A, 0) as A, 
    coalesce(B, 0) as B, 
    coalesce(C, 0) as C 
  from history_itemvalue_pivot 
);

select * from history_itemvalue_pivot_pretty;

+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 |    0 |
|      2 |    9 |    0 |   40 |
+--------+------+------+------+

Och vi är klara -- vi har byggt en snygg, vacker pivottabell med MySQL.

Att tänka på när du tillämpar denna procedur:

  • vilket värde som ska användas i de extra kolumnerna. Jag använde itemvalue i det här exemplet
  • vilket "neutralt" värde som ska användas i de extra kolumnerna. Jag använde NULL , men det kan också vara 0 eller "" , beroende på din exakta situation
  • vilken aggregatfunktion som ska användas vid gruppering. Jag använde sum , men count och max används också ofta (max används ofta när man bygger enrads "objekt" som hade spridits över många rader)
  • använder flera kolumner för y-värden. Den här lösningen är inte begränsad till att använda en enda kolumn för y-värdena – anslut bara de extra kolumnerna till group by klausul (och glöm inte att select dem)

Kända begränsningar:

  • den här lösningen tillåter inte n kolumner i pivottabellen -- varje pivotkolumn måste läggas till manuellt när bastabellen utökas. Så för 5 eller 10 x-värden är den här lösningen bra. För 100, inte så trevligt. Det finns vissa lösningar med lagrade procedurer som genererar en fråga, men de är fula och svåra att få rätt. Jag känner för närvarande inte till ett bra sätt att lösa det här problemet när pivottabellen behöver ha många kolumner.


  1. Vad är det bästa sättet att avgöra vilken version av Oracle-klienten jag kör?

  2. SQL:Välj endast kolumner med NULL-värden

  3. Övervakning av Percona-distribution för PostgreSQL - nyckelmått

  4. Hur man återställer en SQL Server-databas på en Mac med SQL Operations Studio