sql >> Database >  >> RDS >> Mysql

MySQL - Rijen naar kolommen

Ik ga een wat langere en meer gedetailleerde uitleg toevoegen van de stappen die moeten worden genomen om dit probleem op te lossen. Mijn excuses als het te lang is.

Ik zal beginnen met de basis die je hebt gegeven en deze gebruiken om een ​​aantal termen te definiëren die ik voor de rest van dit bericht zal gebruiken. Dit wordt de basistabel :

select * from history;

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

Dit wordt ons doel, de mooie draaitabel :

select * from history_itemvalue_pivot;

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

Waarden in de history.hostid kolom wordt y-waarden in de draaitabel. Waarden in de history.itemname kolom wordt x-waarden (om voor de hand liggende redenen).

Wanneer ik het probleem van het maken van een draaitabel moet oplossen, pak ik het aan met behulp van een proces in drie stappen (met een optionele vierde stap):

  1. selecteer de kolommen van belang, d.w.z. y-waarden en x-waarden
  2. breid de basistabel uit met extra kolommen -- één voor elke x-waarde
  3. groepeer en aggregeer de uitgebreide tabel -- één groep voor elke y-waarde
  4. (optioneel) maak de samengevoegde tabel mooier

Laten we deze stappen toepassen op uw probleem en kijken wat we krijgen:

Stap 1:selecteer interessante kolommen . In het gewenste resultaat, hostid levert de y-waarden en itemname levert de x-waarden .

Stap 2:breid de basistabel uit met extra kolommen . We hebben meestal één kolom per x-waarde nodig. Bedenk dat onze x-waarde kolom itemname is :

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

Houd er rekening mee dat we het aantal rijen niet hebben gewijzigd - we hebben alleen extra kolommen toegevoegd. Let ook op het patroon van NULL s -- een rij met itemname = "A" heeft een niet-null-waarde voor nieuwe kolom A , en null-waarden voor de andere nieuwe kolommen.

Stap 3:groepeer en aggregeer de uitgebreide tabel . We moeten group by hostid , omdat het de y-waarden levert:

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

(Merk op dat we nu één rij per y-waarde hebben.) Oké, we zijn er bijna! We hoeven alleen maar van die lelijke NULL af te komen v.

Stap 4:mooier maken . We gaan alle null-waarden vervangen door nullen, zodat de resultatenset mooier is om naar te kijken:

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

En we zijn klaar -- we hebben een mooie, mooie draaitabel gebouwd met MySQL.

Overwegingen bij het toepassen van deze procedure:

  • welke waarde te gebruiken in de extra kolommen. Ik gebruikte itemvalue in dit voorbeeld
  • welke "neutrale" waarde moet worden gebruikt in de extra kolommen. Ik gebruikte NULL , maar het kan ook 0 . zijn of "" , afhankelijk van uw exacte situatie
  • welke aggregatiefunctie moet worden gebruikt bij het groeperen. Ik gebruikte sum , maar count en max worden ook vaak gebruikt (max wordt vaak gebruikt bij het bouwen van "objecten" met één rij die over meerdere rijen waren verspreid)
  • meerdere kolommen gebruiken voor y-waarden. Deze oplossing is niet beperkt tot het gebruik van een enkele kolom voor de y-waarden -- plug de extra kolommen gewoon in de group by clausule (en vergeet niet te select hen)

Bekende beperkingen:

  • deze oplossing staat geen n kolommen toe in de draaitabel -- elke draaitabel moet handmatig worden toegevoegd bij het uitbreiden van de basistabel. Dus voor 5 of 10 x-waarden is deze oplossing leuk. Voor 100, niet zo leuk. Er zijn enkele oplossingen met opgeslagen procedures die een query genereren, maar ze zijn lelijk en moeilijk om goed te krijgen. Ik weet momenteel geen goede manier om dit probleem op te lossen wanneer de draaitabel veel kolommen moet hebben.


  1. Eenvoudige parametrering en triviale plannen - deel 2

  2. Twee rijen samenvoegen tot één terwijl u null-waarden vervangt

  3. PARSE() vs TRY_PARSE() in SQL Server:wat is het verschil?

  4. Een SSH-tunnel maken voor MySQL Remote Access