Mysql
 sql >> Baza danych >  >> RDS >> Mysql

MySQL — wiersze do kolumn

Dodam nieco dłuższe i bardziej szczegółowe wyjaśnienie kroków, które należy podjąć, aby rozwiązać ten problem. Przepraszam, jeśli to za długo.

Zacznę od bazy, którą podałeś i użyję jej do zdefiniowania kilku terminów, których będę używał w dalszej części tego postu. To będzie tabela podstawowa :

select * from history;

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

To będzie nasz cel, ładna tabela przestawna :

select * from history_itemvalue_pivot;

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

Wartości w history.hostid kolumna zmieni się w wartości y w tabeli przestawnej. Wartości w history.itemname kolumna zmieni się w wartości x (z oczywistych powodów).

Kiedy muszę rozwiązać problem tworzenia tabeli przestawnej, radzę sobie z nim w trzyetapowym procesie (z opcjonalnym czwartym krokiem):

  1. wybierz interesujące kolumny, tj. wartości y i wartości x
  2. rozszerz tabelę podstawową o dodatkowe kolumny — po jednej dla każdej wartości x
  3. grupuj i agreguj rozszerzoną tabelę – jedna grupa dla każdej wartości y
  4. (opcjonalnie) upiększ tabelę zagregowaną

Zastosujmy te kroki do Twojego problemu i zobaczmy, co otrzymamy:

Krok 1:wybierz interesujące kolumny . W żądanym wyniku hostid dostarcza wartości y i itemname dostarcza wartości x .

Krok 2:rozszerz tabelę podstawową o dodatkowe kolumny . Zwykle potrzebujemy jednej kolumny na wartość x. Przypomnij sobie, że nasza kolumna x-value to 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 |
+--------+----------+-----------+------+------+------+

Zwróć uwagę, że nie zmieniliśmy liczby wierszy — po prostu dodaliśmy dodatkowe kolumny. Zwróć także uwagę na wzorzec NULL s -- wiersz z itemname = "A" ma wartość inną niż null dla nowej kolumny A i wartości null dla innych nowych kolumn.

Krok 3:pogrupuj i agreguj rozszerzoną tabelę . Musimy group by hostid , ponieważ dostarcza wartości y:

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

(Zauważ, że mamy teraz jeden wiersz na wartość y). Dobra, już prawie jesteśmy! Musimy tylko pozbyć się tych brzydkich NULL s.

Krok 4:upiększ . Zamienimy po prostu wszystkie wartości null na zera, aby zestaw wyników był przyjemniejszy do oglądania:

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

I gotowe — zbudowaliśmy ładną, ładną tabelę przestawną za pomocą MySQL.

Uwagi dotyczące stosowania tej procedury:

  • jakiej wartości użyć w dodatkowych kolumnach. Użyłem itemvalue w tym przykładzie
  • jakiej „neutralnej” wartości użyć w dodatkowych kolumnach. Użyłem NULL , ale może to być również 0 lub "" , w zależności od Twojej dokładnej sytuacji
  • jakiej funkcji agregującej użyć podczas grupowania. Użyłem sum , ale count i max są również często używane (max jest często używany podczas budowania jednorzędowych „obiektów”, które były rozłożone na wiele wierszy)
  • używanie wielu kolumn dla wartości y. To rozwiązanie nie ogranicza się do używania pojedynczej kolumny dla wartości y — po prostu podłącz dodatkowe kolumny do group by klauzula (i nie zapomnij select ich)

Znane ograniczenia:

  • to rozwiązanie nie zezwala na n kolumn w tabeli przestawnej — każdą kolumnę przestawną należy dodać ręcznie podczas rozszerzania tabeli podstawowej. Tak więc dla 5 lub 10 wartości x to rozwiązanie jest dobre. Za 100, nie tak miło. Istnieje kilka rozwiązań z procedurami składowanymi generującymi zapytania, ale są one brzydkie i trudne do wykonania. Obecnie nie znam dobrego sposobu na rozwiązanie tego problemu, gdy tabela przestawna musi mieć wiele kolumn.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak zoptymalizować wydajność COUNT(*) w InnoDB za pomocą index

  2. Szukaj z wartością oddzieloną przecinkami mysql

  3. Jak połączyć się ze źródłem danych MySQL w Visual Studio

  4. MySQL CAST vs CONVERT

  5. Jak uzyskać aktualny numer sekwencji Auto_Increment dla tabeli MySQL / MariaDB?