sql >> Database teknologi >  >> RDS >> Mysql

MySQL - Rækker til kolonner

Jeg vil tilføje en noget længere og mere detaljeret forklaring af de trin, der skal tages for at løse dette problem. Jeg beklager, hvis den er for lang.

Jeg starter med den base, du har givet, og bruger den til at definere et par udtryk, som jeg vil bruge i resten af ​​dette indlæg. Dette vil være basistabellen :

select * from history;

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

Dette vil være vores mål, den smukke pivottabel :

select * from history_itemvalue_pivot;

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

Værdier i history.hostid kolonne bliver y-værdier i pivottabellen. Værdier i history.itemname kolonne bliver x-værdier (af indlysende årsager).

Når jeg skal løse problemet med at oprette en pivottabel, løser jeg det ved hjælp af en tre-trins proces (med et valgfrit fjerde trin):

  1. vælg kolonnerne af interesse, dvs. y-værdier og x-værdier
  2. udvid basistabellen med ekstra kolonner -- én for hver x-værdi
  3. grupper og aggregér den udvidede tabel -- én gruppe for hver y-værdi
  4. (valgfrit) forskønne den aggregerede tabel

Lad os anvende disse trin på dit problem og se, hvad vi får:

Trin 1:Vælg interessekolonner . I det ønskede resultat, hostid giver y-værdierne og itemname giver x-værdierne .

Trin 2:Udvid basistabellen med ekstra kolonner . Vi har typisk brug for én kolonne pr. x-værdi. Husk, at vores x-værdi kolonne er 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 |
+--------+----------+-----------+------+------+------+

Bemærk, at vi ikke ændrede antallet af rækker - vi tilføjede blot ekstra kolonner. Bemærk også mønsteret for NULL s -- en række med itemname = "A" har en ikke-nul værdi for ny kolonne A , og null-værdier for de andre nye kolonner.

Trin 3:Grupper og saml den udvidede tabel . Vi skal group by hostid , da det giver y-værdierne:

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 |
+--------+------+------+------+

(Bemærk, at vi nu har én række pr. y-værdi.) Okay, vi er der næsten! Vi skal bare af med de grimme NULL s.

Trin 4:forskønne . Vi vil bare erstatte alle nulværdier med nuller, så resultatsættet er pænere at se 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 |
+--------+------+------+------+

Og vi er færdige -- vi har bygget en flot, smuk pivottabel ved hjælp af MySQL.

Overvejelser ved anvendelse af denne procedure:

  • hvilken værdi der skal bruges i de ekstra kolonner. Jeg brugte itemvalue i dette eksempel
  • hvilken "neutral" værdi der skal bruges i de ekstra kolonner. Jeg brugte NULL , men det kan også være 0 eller "" , afhængigt af din nøjagtige situation
  • hvilken aggregeringsfunktion der skal bruges ved gruppering. Jeg brugte sum , men count og max bruges også ofte (max bruges ofte, når man bygger "objekter" med én række, der var spredt ud over mange rækker)
  • brug af flere kolonner til y-værdier. Denne løsning er ikke begrænset til at bruge en enkelt kolonne til y-værdierne – sæt blot de ekstra kolonner ind i group by klausul (og glem ikke at select dem)

Kendte begrænsninger:

  • denne løsning tillader ikke n kolonner i pivottabellen -- hver pivotkolonne skal tilføjes manuelt, når basistabellen udvides. Så for 5 eller 10 x-værdier er denne løsning fin. For 100, ikke så pænt. Der er nogle løsninger med lagrede procedurer, der genererer en forespørgsel, men de er grimme og svære at få rigtige. Jeg kender i øjeblikket ikke en god måde at løse dette problem på, når pivottabellen skal have mange kolonner.


  1. PostgreSQL-skemaer / navnerum med Django

  2. Ydelsesforskel:betingelse placeret ved INNER JOIN vs WHERE-klausul

  3. Log alle forespørgsler i mysql

  4. Forskellen mellem VARCHAR og TEXT i MySQL