Mysql
 sql >> база данни >  >> RDS >> Mysql

MySQL - Редове към колони

Ще добавя малко по-дълго и по-подробно обяснение на стъпките, които трябва да предприемете за решаване на този проблем. Извинявам се, ако е твърде дълго.

Ще започна с базата, която сте дали и ще я използвам, за да дефинирам няколко термина, които ще използвам до края на тази публикация. Това ще бъде основната таблица :

select * from history;

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

Това ще бъде нашата цел, красивата опорна маса :

select * from history_itemvalue_pivot;

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

Стойности в history.hostid колоната ще стане y-стойности в централната таблица. Стойности в history.itemname колоната ще се превърне в x-стойности (по очевидни причини).

Когато трябва да реша проблема със създаването на въртяща се таблица, се справям с него с помощта на процес от три стъпки (с незадължителна четвърта стъпка):

  1. изберете колоните, които представляват интерес, т.е. y-стойности и x-стойности
  2. разширете основната таблица с допълнителни колони – по една за всяка x-стойност
  3. групирайте и агрегирайте разширената таблица – една група за всяка y-стойност
  4. (по избор) украсете обобщената таблица

Нека приложим тези стъпки към вашия проблем и да видим какво получаваме:

Стъпка 1:изберете колони, представляващи интерес . В желания резултат hostid предоставя y-стойности и itemname предоставя x-стойности .

Стъпка 2:разширете основната таблица с допълнителни колони . Обикновено се нуждаем от една колона на x-стойност. Припомнете си, че нашата колона с x-стойност е 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 |
+--------+----------+-----------+------+------+------+

Имайте предвид, че не сме променили броя на редовете - просто добавихме допълнителни колони. Обърнете внимание и на модела на NULL s -- ред с itemname = "A" има ненулева стойност за нова колона A и нулеви стойности за другите нови колони.

Стъпка 3:групирайте и обобщете разширената таблица . Трябва да group by hostid , тъй като предоставя 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 |
+--------+------+------+------+

(Обърнете внимание, че вече имаме един ред на y-стойност.) Добре, почти сме там! Просто трябва да се отървем от тези грозни NULL с.

Стъпка 4:украсете . Просто ще заменим всички нулеви стойности с нули, така че наборът от резултати да е по-приятен за гледане:

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

И сме готови -- изградихме хубава, хубава централна таблица, използвайки MySQL.

Съображения при прилагането на тази процедура:

  • каква стойност да използвате в допълнителните колони. Използвах itemvalue в този пример
  • каква „неутрална“ стойност да използвате в допълнителните колони. Използвах NULL , но може да бъде и 0 или "" , в зависимост от вашата точна ситуация
  • каква обобщена функция да използвате при групиране. Използвах sum , но count и max също често се използват (max често се използва при изграждане на едноредови „обекти“, които са били разпределени в много редове)
  • използване на множество колони за y-стойности. Това решение не се ограничава до използването на една колона за y-стойностите - просто включете допълнителните колони в group by клауза (и не забравяйте да select тях)

Известни ограничения:

  • това решение не позволява n колони в обобщената таблица – всяка опорна колона трябва да бъде добавена ръчно при разширяване на основната таблица. Така че за 5 или 10 x-стойности това решение е хубаво. За 100 не е толкова хубаво. Има някои решения със съхранени процедури, генериращи заявка, но те са грозни и трудни за оправяне. Понастоящем не знам добър начин за разрешаване на този проблем, когато централната таблица трябва да има много колони.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Защо приблизителният брой редове е много различен в резултатите от phpmyadmin?

  2. MySQL извлича променлива от Съхранена процедура в PHP PDO

  3. MySqlCommand Command.Parameters.Add е остарял

  4. MySQL как да попълним липсващи дати в диапазона?

  5. Комбиниране на операции UNION и LIMIT в MySQL заявка