在MySQL中制作PIVOT表时遇到问题。我有下表。 (这是一张简化的演示表。真实的演示表有4000张股票,可以容纳10个交易日期和20个测量值。)
CREATE TABLE `levermann` (
`RecNum` bigint(20) NOT NULL AUTO_INCREMENT,
`Tradedate` date DEFAULT NULL,
`Stock_Short` varchar(50) DEFAULT NULL,
`Country` varchar(2) DEFAULT NULL,
`LScore2` int(11) DEFAULT NULL,
`MarketCAPUSD` bigint(20) DEFAULT NULL,
PRIMARY KEY (`RecNum`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of levermann
-- ----------------------------
INSERT INTO `levermann` VALUES ('8099', '2018-05-23', 'ANDR.VI', 'VI', '-9', '5109518494');
INSERT INTO `levermann` VALUES ('8100', '2018-05-23', 'BWO.VI', 'VI', '-7', '4241189324');
INSERT INTO `levermann` VALUES ('8101', '2018-05-23', 'CAI.VI', 'VI', '-7', '3222135865');
INSERT INTO `levermann` VALUES ('8102', '2018-05-09', 'CWI.VI', 'VI', '-8', null);
INSERT INTO `levermann` VALUES ('8103', '2018-05-23', 'EBS.VI', 'VI', '-7', '18317742129');
INSERT INTO `levermann` VALUES ('8104', '2018-05-23', 'FLU.VI', 'VI', '-8', '3176359049');
INSERT INTO `levermann` VALUES ('8105', '2018-05-23', 'IIA.VI', 'VI', '-8', '2767477473');
INSERT INTO `levermann` VALUES ('8106', '2018-05-23', 'LNZ.VI', 'VI', '-9', '3027507195');
输出应该是一个表,其中这8个中的每个STOCKCODE(例如ANDR.VI)应该是一列,其中一个可选的测量值(例如LScore2)按交易日期(=行)分组。
我找到了这个Exmapl in MYSQL,但我并不完全理解。我已经完成了更多的工作:
SELECT
tradedate,
GROUP_CONCAT(stock_short) as STOCKCODE
FROM
levermann
GROUP BY
Tradedate;
但是这里的股票代码位于一个单元格中,而不位于标头中。 这是所需输出示例的图像。总列数约为4000(表中的最大列数不超过4096)。交易日期(=行)总计约350天/年,共2年。
显然,这些列应该动态创建,并且不能由AS语句硬编码。
这个难题有解决方案吗? 非常感谢。
更新: 我认为这样的动态运行语句。
SET @sql = NULL;
SELECT GROUP_CONCAT(concat(LScore2,' AS `LScore_',Stock_Short,'`')) into
@sql from levermann;
SET @sql = CONCAT('SELECT tradedate, ', @sql, '
FROM levermann
GROUP BY tradedate');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
但是我不知道如何创建字符串:
LScore AS LScore_ANDR.VI, LScore AS LScore_BWO.VI, ...
我真的很怀疑,但是它可以在MySQL中以某种方式完成。 当然我也可以制作一个php脚本。但是我想学习如何在MySQL中完成。
更新2:我想我可以做到。我不太确定它是否正确,但它是动态创建的。在MySQL中
答案 0 :(得分:1)
我想我明白了
SET SESSION group_concat_max_len = @@max_allowed_packet;
SET @sql = NULL;
SELECT GROUP_CONCAT(concat('MAX(CASE Stock_Short WHEN \'',Stock_Short,'\' THEN \'',LScore2,'\' END) AS `LScore_',Stock_Short,'`')) into @sql from levermanndemo where country = 'VI';
SET @sql = CONCAT('SELECT tradedate, ', @sql, '
FROM levermanndemo
GROUP BY tradedate');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
输出:
更新:不幸的是,如果表看起来像这样,就会麻烦。
我尝试了以下解决方案:
SET SESSION group_concat_max_len = @@max_allowed_packet;
SET @sql = NULL;
SELECT GROUP_CONCAT( DISTINCT concat('MAX(CASE WHEN p.Stock_Short =
\'',f.Stock_Short,'\' AND `Tradedate` = \'', f.tradedate,'\' THEN
\'',f.LScore2,'\' ELSE NULL END) AS `LScore_',f.Stock_Short,'`'))
into @sql from levermanndemo f ;
SET @sql = CONCAT('SELECT p.tradedate, ', @sql, ' FROM levermanndemo p
GROUP BY p.tradedate');
#SELECT @sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
不需要输出-错误。现在有2个具有相同STOCK的列(BWO.VI和BWO.VI1),我想将这两列合并在一起。但是怎么办呢?
答案 1 :(得分:0)
在SQL中,一旦开始读取数据,您将无法编写任何基于其发现的数据值来动态扩展列的查询。准备查询时,所有列都必须固定在查询的选择列表中-在之前读取任何数据。
这意味着您必须了解所有不同的值,并且需要为要包含在数据透视表中的每个值生成一个带有一个列的选择列表。
您可以通过执行以下两个查询来解决此问题:一次获取所有不同的库存值:
SELECT DISTINCT Stock_Short FROM levermann
然后根据该结果,为每个股票价值的on表达式格式化一个looooong SQL查询。从您知道不是动态库存相关列之一的列开始:
SELECT Tradedate,
然后针对firs查询结果中的每一行,添加一列,如:
MAX(CASE Stock_Short WHEN <value> THEN LScore2 END) AS <alias>,
然后最后追加查询的结尾:
FROM levermann
GROUP BY Tradedate;
我的建议是,因为您有4000种不同的库存值,所以您应该按原样从数据库中获取数据,并使用应用程序代码来呈现透视显示。也就是说,循环遍历所有4000个行(而不是列)的SQL查询结果,并将其排列到应用程序空间中的对象中。然后格式化要显示的对象。
答案 2 :(得分:0)
如果StockCodes列表是固定的,是否不能简单地固定新表的列,然后过滤原始表中的数据以复制到新表中?
例如,至少在Excel中手动执行此操作。