動態數據透視表pivot table(行轉換列)

原文地址: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。

+----+---------+---------------+--------+
| id | item_id | property_name | value  |
+----+---------+---------------+--------+
|  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     |
+----+---------+---------------+--------+
=>
+---------+--------+--------+--------+
| 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     |
+---------+--------+--------+--------+

衆所周知,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     |
+---------+--------+--------+--------+



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章