原文地址:http://buysql.com/mysql/14-how-to-automate-pivot-tables.html
MYSQL下如何動態生成標題的數據透視表。
先用以下script生成一張包含若干屬性的表叫"properties"。
CREATE TABLE properties (
id INT(11) NOT NULL AUTO_INCREMENT,
item_id INT(11) DEFAULT NULL,
property_name VARCHAR(255) DEFAULT NULL,
value VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO properties VALUES
(1, 1, 'color', 'blue'),
(2, 1, 'size', 'large'),
(3, 1, 'weight', 65),
(4, 2, 'color', 'orange'),
(5, 2, 'weight', 57),
(6, 2, 'size', 'large'),
(7, 3, 'size', 'small'),
(8, 3, 'color', 'red'),
(9, 3, 'weight', 12),
(10, 4, 'color', 'violet'),
(11, 4, 'size', 'medium'),
(12, 4, 'weight', 34),
(13, 5, 'color', 'green'),
(14, 5, 'weight', 10);
然後我們想根據原始數據生成如下report。
|
=> |
|
衆所周知,MySql裏並沒有自動錶轉換的功能。當然,我們可以用一些額外的程序或工具來連接MySQL去執行數據轉換。但在這裏,我們來探討下如何手動的寫一個查詢來實現數據轉換。該查詢可以這樣實現:
SELECT
item_id,
MAX(IF(property_name = 'color', value, NULL)) AS color,
MAX(IF(property_name = 'size', value, NULL)) AS size,
...
...
...
FROM
properties
GROUP BY
item_id;
很明顯,對於任何一個'property_name'我們都做了定義,如'color', 'size'。如果屬性的類型不變的話,這個查詢已經沒有問題了。但是如果字段'property_name'經常變,並且可能會增加一個新的,那要怎麼處理呢?難道只能每次去改這個查詢語句麼?這種情況下,就可以使用動態生成查詢語句——讀取表中字段'property_name'的所有值,根據該值動態的創建一個查詢語句。
動態生成查詢的實現如下:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(property_name = ''',
property_name,
''', value, NULL)) AS ',
property_name
)
) INTO @sql
FROM properties;
SET @sql = CONCAT('SELECT item_id, ', @sql, ' FROM properties GROUP BY item_id');
執行該語句,會生成如下的查詢語句(爲了閱讀方便,調整了下格式):
SELECT
item_id,
MAX(IF(property_name = 'color', value, NULL)) AS color,
MAX(IF(property_name = 'size', value, NULL)) AS size,
MAX(IF(property_name = 'weight', value, NULL)) AS weight
FROM
properties
GROUP BY
item_id
注意:
MySQL對於GROUP_CONCAT結果用系統變量group_concat_max_len做了限制,默認值是1024。所以,如果你的表有很多列,最好將該值設大一些。
SET @@group_concat_max_len = 5000;
SELECT GROUP_CONCAT(column_name) FROM table;
經過執行動態生成語句,查詢語句被寫到變量@sql裏,現在我們可以用prepared statment來執行該語句:
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
結果:
+---------+--------+--------+--------+
| item_id | color | size | weight |
+---------+--------+--------+--------+
| 1 | blue | large | 65 |
| 2 | orange | large | 57 |
| 3 | red | small | 12 |
| 4 | violet | medium | 34 |
| 5 | green | NULL | 10 |
+---------+--------+--------+--------+