我只有一个数据表(以下简化)
| id | date | product |
|----|-------------|---------|
| 1 | 2019-01-02 | prod 1 |
| 2 | 2019-01-02 | prod 2 |
| 3 | 2019-01-22 | prod 1 |
| 4 | 2019-02-02 | prod 1 |
| 5 | 2019-02-02 | prod 1 |
| 6 | 2019-03-02 | prod 1 |
我希望最终结果看起来像这样...
| product | 2019-01 | 2019-02 | 2019-03 |
|---------|---------|---------|---------|
| prod 1 | 2 | 3 | 0 |
| prod 2 | 1 | 0 | 0 |
简而言之,我想遍历日期范围内的所有产品(所有日期都包含在一个表中)。如果一个月没有结果,则返回0。我相信COALESCE可能是解决此问题的方法。
我尝试了两种单独的方法...在单个查询中返回所有数据并循环访问该数据,但是如果没有数据,我将永远不会返回字符串或我可以使用的东西(空)。
SELECT
product_name,
count(product_name) AS count
DATE_FORMAT(date,'%Y-%m') AS date
FROM products
GROUP BY DATE_FORMAT(date,'%Y-%m'), company_name
ORDER BY date;
| product | date | count |
|---------|---------|-------|
| prod 1 | 2019-01 | 2 |
| prod 2 | 2019-01 | 1 |
| prod 1 | 2019-02 | 3 |
| prod 2 | 2019-02 | 0 | <--- this row doesn't return
或者,我尝试遍历所有产品,然后分别遍历日期,但是如果表中没有日期,则不会再返回任何数据,因此我的表会偏斜。
我已经看到其他人将日期存储在另一个表中,然后遍历该表,这感觉有点过头了,因为我在该表中拥有所有日期,因此我尝试将表连接到自身上,但这也不起作用。
在此先感谢您的帮助。
答案 0 :(得分:0)
这基本上是数据透视表。
有关如何实现此目标的不错的教程,可以在这里找到:http://www.artfulsoftware.com/infotree/qrytip.php?id=78
这是您的数据透视表的动态解决方案。 只需使用@Nick建议的查询并为其创建临时表
create temporary table tmp as
SELECT
p.product_name,
count(p2.product_name) AS count,
d.date
FROM (SELECT DISTINCT DATE_FORMAT(date,'%Y-%m') AS date
FROM products) d
CROSS JOIN (SELECT DISTINCT product_name
FROM products) p
LEFT JOIN products p2 ON DATE_FORMAT(p2.date,'%Y-%m') = d.date AND p2.product_name = p.product_name
GROUP BY p.product_name, d.date
ORDER BY p.product_name, d.date;
现在是动态SP,可以将Row转换为列,以防将来出现任何新产品。
delimiter $$
DROP PROCEDURE IF EXISTS pivot $$
CREATE PROCEDURE pivot(IN schema_name VARCHAR(64)
, IN table_name VARCHAR(64)
, IN id_name VARCHAR(64)
, IN key_name VARCHAR(64)
, IN value_name VARCHAR(64))
pivot:BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET @error := 1;
SET @error := 0;
SELECT MAX(character_maximum_length)
INTO @maxlen
FROM information_schema.columns
WHERE table_schema = schema_name
AND table_name = table_name
AND column_name = key_name
AND data_type IN ('char', 'varchar');
SET @maxlen = IFNULL(@maxlen,500);
IF @error OR !@maxlen OR @maxlen IS NULL THEN
SELECT '@error OR @maxlen=0 OR @maxlen IS NULL', @error, @maxlen;
LEAVE pivot;
END IF;
DROP TEMPORARY TABLE IF EXISTS temp_pivot;
SET @sql := CONCAT('CREATE TEMPORARY TABLE temp_pivot (key_name VARCHAR(',
@maxlen,
')) ENGINE=Memory SELECT DISTINCT `',
key_name,
'` key_name FROM `',
schema_name,
'`.`',
table_name,
'`;');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DROP PREPARE stmt;
SELECT GROUP_CONCAT(CONCAT( ', MAX(CASE `',
key_name,
'` WHEN ''',
temp_pivot.key_name,
''' THEN `',
value_name,
'` else 0 END) `',
temp_pivot.key_name,
'`') SEPARATOR '')
INTO @sql
FROM temp_pivot;
DROP TEMPORARY TABLE IF EXISTS Pivot_Check;
SET @sql := CONCAT('CREATE TEMPORARY TABLE Pivot_Check AS ','SELECT `',
id_name,
'`',
@sql,
' FROM `',
schema_name,
'`.`',
table_name,
'` GROUP BY `',
id_name,
'`;');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DROP PREPARE stmt;
SET @error := NULL;
SET @maxlen := NULL;
SET @sql := NULL;
END $$
delimiter
然后致电SP
call pivot('schema_name','table_name','product','count','date');
您的数据透视表已经准备就绪,只需使用
select * from Pivot_Check