ฉันจะเพิ่มคำอธิบายที่ยาวขึ้นและมีรายละเอียดมากขึ้นเกี่ยวกับขั้นตอนในการแก้ไขปัญหานี้ ฉันขอโทษถ้ามันยาวเกินไป
ฉันจะเริ่มด้วยพื้นฐานที่คุณให้และใช้เพื่อกำหนดคำศัพท์สองสามคำที่ฉันจะใช้สำหรับส่วนที่เหลือของโพสต์นี้ นี่จะเป็นตารางฐาน :
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 (สำหรับเหตุผลที่ชัดเจน)
เมื่อฉันต้องแก้ปัญหาในการสร้างตารางสาระสำคัญฉันจัดการมันโดยใช้กระบวนการสามขั้นตอน (ด้วยขั้นตอนที่สี่ที่เป็นตัวเลือก):
- เลือกคอลัมน์ที่สนใจเช่นค่า yและค่าx
- ขยายตารางฐานด้วยคอลัมน์เพิ่มเติม - หนึ่งคอลัมน์สำหรับแต่ละค่า x
- กลุ่มและรวมตารางเสริม - หนึ่งกลุ่มสำหรับแต่ละค่า y
- (ไม่บังคับ) ให้ใส่ข้อมูลตารางรวมไว้ล่วงหน้า
ลองใช้ขั้นตอนเหล่านี้กับปัญหาของคุณและดูว่าเราได้รับอะไรบ้าง:
ขั้นตอนที่ 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
และค่า 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) โอเคเราเกือบจะถึงแล้ว! เราแค่ต้องกำจัดสิ่งที่น่าเกลียดเหล่านั้น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 ไม่ใช่คนดี มีวิธีแก้ปัญหาบางอย่างที่มีขั้นตอนการจัดเก็บสร้างแบบสอบถาม แต่มันน่าเกลียดและยากที่จะเข้าใจ ขณะนี้ฉันยังไม่รู้วิธีที่ดีในการแก้ปัญหานี้เมื่อตารางเดือยจำเป็นต้องมีคอลัมน์จำนวนมาก