この問題を解決するための手順について、もう少し長く詳細な説明を追加します。長すぎる場合は申し訳ありません。
いただいたベースから始めて、それを使用して、この投稿の残りの部分で使用するいくつかの用語を定義します。これがベース テーブルになります。
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 値になります(理由は明らかです)。
ピボット テーブルを作成する際の問題を解決する必要がある場合は、次の 3 段階のプロセス (オプションで 4 番目の手順を含む) を使用して取り組みます。
- 対象の列、つまりy 値とx値を選択します
- 追加の列でベース テーブルを拡張します。x 値ごとに 1 つです。
- 拡張テーブルをグループ化して集計します -- 各y 値に対して 1 つのグループ
- (オプション) 集計テーブルを整形する
これらの手順を問題に適用して、結果を見てみましょう。
ステップ 1: 関心のある列を選択します。目的の結果でhostid
は、y 値をitemname
提供し、x値を提供します。
ステップ 2: 追加の列でベース テーブルを拡張します。通常、x 値ごとに 1 つの列が必要です。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 |
+--------+----------+-----------+------+------+------+
行数は変更していないことに注意してください。列を追加しただけです。sのパターンにも注意してくださいNULL
-- を持つ行itemname = "A"
は、 new column に null 以外の値を持ちA
、他の新しい列には null 値を持ちます。
ステップ 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 値ごとに 1 つの行があることに注意してください。) よし、あと少しです! これらの醜い を取り除く必要があるだけですNULL
。
ステップ 4: きれいにします。結果セットが見やすくなるように、null 値をゼロに置き換えるだけです。
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
多くの行に分散された 1 行の「オブジェクト」を構築するときによく使用されます)。
- y 値に複数の列を使用します。このソリューションは、y 値に 1 つの列を使用することに限定されません。余分な列を
group by
句に挿入するだけです (忘れないでselect
ください) 。
既知の制限:
- このソリューションでは、ピボット テーブルに n 列を許可しません。ベース テーブルを拡張するときに、各ピボット列を手動で追加する必要があります。したがって、x 値が 5 または 10 の場合、このソリューションは適切です。100の場合、あまり良くありません。クエリを生成するストアド プロシージャを使用するソリューションがいくつかありますが、それらは見苦しく、正しく理解するのが困難です。現在、ピボット テーブルに多数の列が必要な場合に、この問題を解決する良い方法がわかりません。