我有一个包含3列的表格(标签)。这是一个小样本:
element_name | data_timestamp | data_in
Port1 2013-10-01 4335
Port1 2013-10-02 4335
Port1 2013-10-03 4365
Port1 2013-10-04 4375
Port2 2013-10-01 3335
Port2 2013-10-02 3335
Port2 2013-10-03 3365
Port2 2013-10-04 3375
Port3 2013-10-01 7335
Port3 2013-10-02 7335
Port3 2013-10-03 7365
Port3 2013-10-04 7375
我可以拥有任何不同数量的“elemment_name”,因此我需要一个具有动态列数的交叉表。在我的样本中,我想要:
Port1 | Port2 | Port3 | Date
4335 3335 7335 2013-10-01
4335 3335 7335 2013-10-02
4365 3365 7365 2013-10-03
4375 3375 7375 2013-10-04
我还没有找到一个干净的方法,所以我写了一个存储例程:
CREATE DEFINER=`root`@`localhost` PROCEDURE `makecrosstab`()
BEGIN
DECLARE hdrs TEXT;
DECLARE value_name varchar(100);
DECLARE value_date datetime;
DECLARE datapoint INT(11);
DECLARE no_more_rows BOOLEAN;
DECLARE data_cur CURSOR FOR
SELECT REPLACE(REPLACE(replace(replace(replace(tab.element_name,'\n',' '),' ','_'),'.','_'),'(',''),')','') as col,
tab.data_timestamp, tab.data_in
FROM tab
order by tab.element_name, tab.data_timestamp;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows = TRUE;
SET @colm = '';
SET @ddl = '';
drop temporary table if exists grid;
SELECT concat(group_concat(distinct REPLACE(REPLACE(replace(replace(replace(tab.element_name,'\n',' '),' ','_'),'.','_'),'(',''),')','')),',') into hdrs
FROM tab;
WHILE (LOCATE(',', hdrs) > 0)
DO
SET @value = ELT(1, hdrs);
SET @STR = SUBSTRING(hdrs, 1, LOCATE(',',hdrs)-1);
SET hdrs = SUBSTRING(hdrs, LOCATE(',', hdrs) + 1);
SET @ddl = concat(@ddl , @STR , ' INT(11) default 0,');
END WHILE;
SET @ddl = concat('create temporary table grid (',@ddl , ' measurement_date datetime);');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
insert into grid (measurement_date) select distinct data_timestamp from tab;
OPEN data_cur;
the_loop: LOOP
FETCH data_cur
INTO value_name,value_date,datapoint;
IF no_more_rows THEN
CLOSE data_cur;
LEAVE the_loop;
END IF;
SET @colm = concat('update grid set ',value_name ,' = ', datapoint, ' where measurement_date = ''',value_date,''';');
PREPARE stmt FROM @colm;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP the_loop;
select * from grid;
END
我不禁想到有更好的方法,但如果您不知道结果集将包含多少列,则无法找到任何解决方案。
有谁知道更简单的解决方案?
答案 0 :(得分:0)
也许以下存储过程可以为您提供一些简化方法的想法:
/* CODE FOR DEMONSTRATION PURPOSES */
DELIMITER $$
CREATE PROCEDURE `sp_cross_tab`()
BEGIN
DECLARE `done` INT DEFAULT FALSE;
DECLARE `en` VARCHAR(5);
DECLARE `crosstab` TEXT DEFAULT '';
DECLARE `cur` CURSOR FOR
SELECT `element_name`
FROM `tab`
GROUP BY `element_name`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET `done` = TRUE;
OPEN `cur`;
`read_loop`: LOOP
FETCH `cur` INTO `en`;
IF `done` THEN
LEAVE `read_loop`;
END IF;
SET `crosstab` := CONCAT(`crosstab`, 'SUM(IF(`element_name` = \'', `en`, '\', `data_in`, 0)) AS `', `en`, '`,');
END LOOP;
CLOSE `cur`;
SET @`query` := CONCAT('SELECT ', `crosstab`, ' `data_ts` FROM `tab` GROUP BY `data_ts`');
PREPARE `stmt` FROM @`query`;
SET @`query` := NULL;
EXECUTE `stmt`;
DEALLOCATE PREPARE `stmt`;
END$$
DELIMITER ;