2011-05-27 183 views
1

我想編寫一個查詢來創建數據的「表」如下:MySQL的數據透視表

SELECT cs.`category_id`, cs.`ProcessDate`, cs.`PercentChange` 
    FROM `Category_Statistics` cs 
WHERE cs.`ProcessDate` >= '2011-05-10' 
    AND cs.`ProcessDate` <= '2011-05-14' 

這將返回類似:

CategoryId | ProcessDate | PercentChange 
------------------------------------------- 
category_4 | 2011-05-10 |  10 
category_4 | 2011-05-11 |  18 
category_4 | 2011-05012 |  12 
... 
category_7 | 2011-05-10 |  21 
category_7 | 2011-05-11 |  7 
... 
category_12 | 2011-05-10 |  7 
category_12 | 2011-05-11 |  15 

現在我希望結果是這樣的(從MySQL查詢,而不是由應用程序操作):

CategoryId | 2011-05-10 | 2011-05-11 | 2011-05-12 | 2011-05-13 | 2011-05-14 | 
-------------------------------------------------------------------------------- 
category_4 |  10  |  18  |  12  |  9  |  14 | 
category_7 |  21  |  7  |  16  |  14 |  13 | 
categeory_12 |  7  |  15  |  11  |  19 |  8 | 
-------------------------------------------------------------------------------- 

有兩個警告這樣:

  1. 日期範圍可以擴大或縮小 (取決於查詢)

  2. PercentChange可能在某些情況下, 空(可以說category_7/ 2011-05-12可能沒有設置值)

所以,最後我不太清楚如何構建查詢的選擇部分,以反映列的動態數(我知道它是與CONCAT)。

編輯 - >部分的工作代碼 - >

SELECT `CategoryId`, 
    MAX(IF(c.`ProcessedOn` = '2011-04-20', c.`PercentChange`, NULL)) AS '2011-04-20', 
    MAX(IF(c.`ProcessedOn` = '2011-04-21', c.`PercentChange`, NULL)) AS '2011-04-21', 
    MAX(IF(c.`ProcessedOn` = '2011-04-22', c.`PercentChange`, NULL)) AS '2011-04-22', 
    MAX(IF(c.`ProcessedOn` = '2011-04-23', c.`PercentChange`, NULL)) AS '2011-04-23', 
    MAX(IF(c.`ProcessedOn` = '2011-04-24', c.`PercentChange`, NULL)) AS '2011-04-24' 
    FROM `Category_Gravity` c 
WHERE c.`ProcessedOn` >= '2011-04-20' 
    AND c.`ProcessedOn` <= '2011-04-24' 
GROUP BY `CategoryId` 

我現在需要做的是打開

MAX(IF(c.`ProcessedOn` = '2011-04-20', c.`PercentChange`, NULL)) AS '2011-04-20', 

到的東西更多動態的(因爲我的日期範圍將發生變化)

回答

5

看看這個類似的線程,我寫了一個sp來完成任務

Join two tables (with a 1-M relationship) where the second table needs to be 'flattened' into one row

編輯。更新答案

create table `pivot` (
    `id` int(11) not null auto_increment, 
    `categoryid` int(11) default null, 
    `processdate` date default null, 
    `percentchange` int(11) default null, 
    primary key (`id`) 
) engine=myisam auto_increment=9 default charset=latin1; 

/*Data for the table `pivot` */ 

insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (1,4,'2011-05-10',1); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (2,4,'2011-05-11',22); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (3,4,'2011-05-12',3); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (4,7,'2011-05-10',4); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (5,7,'2011-05-11',5); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (6,12,'2011-05-10',6); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (7,12,'2011-05-12',7); 
insert into `pivot`(`id`,`categoryid`,`processdate`,`percentchange`) values (8,4,'2011-05-13',12); 



delimiter // 
drop procedure if exists dynamic_view2// 
create procedure dynamic_view2(in sdate date,in edate date) 
begin 
declare finish int default 0; 
declare cdate date; 
declare str varchar(10000) default "select categoryid,"; 
declare curs cursor for select processdate from pivot where processdate between sdate and edate group by processdate; 
declare continue handler for not found set finish = 1; 
open curs; 
my_loop:loop 
fetch curs into cdate; 
if finish = 1 then 
leave my_loop; 
end if; 
set str = concat(str, "max(case when processdate = '",cdate,"' then percentchange else null end) as `",cdate,"`,"); 
end loop; 
close curs; 
set str = substr(str,1,char_length(str)-1); 
set @str = concat(str," from pivot 
      group by categoryid"); 

prepare stmt from @str; 
execute stmt; 
deallocate prepare stmt; 
end;// 
delimiter ; 


mysql> call dynamic_view2('2011-05-10','2011-05-13'); 
+------------+------------+------------+------------+------------+ 
| categoryid | 2011-05-10 | 2011-05-11 | 2011-05-12 | 2011-05-13 | 
+------------+------------+------------+------------+------------+ 
|   4 |   1 |   22 |   3 |   12 | 
|   7 |   4 |   5 |  NULL |  NULL | 
|   12 |   6 |  NULL |   7 |  NULL | 
+------------+------------+------------+------------+------------+ 
3 rows in set (0.00 sec) 
+0

@nick rulez我想跟着你的榜樣,但是我,因爲我沒有使用1-M的關係,只是一個表有一列,我想掙扎一點點列標題。我並沒有打折你的解決方案,只是無法在你的程序中實施我的例子。 – 2011-05-27 23:13:33

+0

我已經更新了我的答案。希望它可以幫助你。 – 2011-05-27 23:18:49

+0

@nick rulez看起來不錯,我只是通過它(所以我理解的過程而不是複製/粘貼),有一件事我不太明白,使用VARCHAR(10000)。我明白到底該怎麼做,但爲什麼不使用TEXT(或者在SELECT語句中不起作用?),我還以爲VARCHAR限制爲255個字符(回到mysql手冊) – 2011-05-27 23:47:46