在MySQL中将数据从行转置为列(不进行任何聚合)

时间:2018-11-07 12:13:20

标签: mysql

我需要在MySQL中将数据从行转置为列,但不进行任何聚合。

例如,我有下表:

 CREATE TABLE `MyTable` ( `id` INT NOT NULL AUTO_INCREMENT ,`city` VARCHAR(10) NOT NULL , 
`category` VARCHAR(10) NOT NULL , `item`VARCHAR(10) NOT NULL , `price` DECIMAL(5,2) NOT NULL , 
`date` DATE NOT NULL ,PRIMARY KEY (`id`)) ENGINE = InnoDB;

具有以下数据:

INSERT INTO `MyTable` (`id`, `city`, `category`, `item`, `price`, `date`) VALUES (NULL, 'A', 'Cat1','It1', '10.00', '2018-01-01'), 
(NULL, 'A', 'Cat1','It1', '20.00', '2018-01-02'), 
(NULL, 'A', 'Cat1','It2', '30.00', '2018-01-03'),
(NULL, 'A', 'Cat2','It1', '40.00', '2018-01-04'),
(NULL, 'B', 'Cat1','It1', '50.00', '2018-01-05'),
(NULL, 'A', 'Cat1', 'It1', '100.00', '2018-02-11'), 
(NULL, 'A', 'Cat1','It1', '200.00', '2018-02-12'), 
(NULL, 'A', 'Cat1','It2', '300.00', '2018-02-13'),
(NULL, 'A', 'Cat2','It1', '400.00', '2018-02-14'),
(NULL, 'B', 'Cat1','It1', '500.00', '2018-02-15')

当我使用此查询时

 SELECT city, category, item, sum(CASE WHEN EXTRACT(YEAR_MONTH FROM `date`) = "201801" 
THEN price ELSE 0 END) AS "Jan", sum(CASE WHEN EXTRACT(YEAR_MONTH FROM `date`) = "201802" 
THEN price ELSE 0 END) AS "Feb" FROM MyTable WHERE 1 GROUP BY city, category, item

然后我得到了“ Item1”的汇总结果:

enter image description here

但是我需要所有交易而没有任何汇总: enter image description here

我应该如何构成查询以获得正确的结果?

1 个答案:

答案 0 :(得分:0)

您尝试做的一般类称为 PIVOT 。在PIVOT中,行的子集的作用类似于表,这意味着将单个列中的数据分成几列。 JOIN可以在这里为您提供帮助:

SELECT
  tblItems.city, tblItems.category, tblItems.item,
  tblJan.price AS Jan,
  tblFeb.price AS Feb
FROM
  (SELECT city, category, item
   FROM MyTable
   GROUP BY city, category, item) AS tblItems
INNER JOIN
  (SELECT city, category, item, price
   FROM MyTable
   WHERE EXTRACT(YEAR_MONTH FROM `date`) = "201801") AS tblJan
ON (tblItems.city = tblJan.city AND tblItems.category = tblJan.category AND tblItems.item = tblJan.item)
INNER JOIN
  (SELECT city, category, item, price
   FROM MyTable
   WHERE EXTRACT(YEAR_MONTH FROM `date`) = "201802") AS tblFeb
ON (tblItems.city = tblFeb.city AND tblItems.category = tblFeb.category AND tblItems.item = tblFeb.item)
ORDER BY tblItems.city, tblItems.category, tblItems.item;

SQL小提琴:http://sqlfiddle.com/#!9/f77978a/3

但是,您的下一个问题将是:“如何动态地执行此操作,如果我不提前知道将有多少个子表?”在当前情况下,这可能并不重要,因为一年中有固定的月份数。但是迟早,您将要动态执行PIVOT。

某些RDBMS具有内置的PIVOT函数,但是不幸的是,MySQL不是其中之一。因此,对于MySQL,您需要逻辑来动态构建PIVOT查询,然后执行所构建的查询。该逻辑可以在MySQL内部的存储过程中,也可以在具有MySQL功能的外部语言中使用(大多数现代语言都可以)。

编辑:或者,您可以考虑遵循@Madhur Bhaiya的评论,并将信息的显示委托给从数据库中获取数据的程序; SQL功能强大,但与其他所有功能一样,它也不是满足您所有需求的合适地方。