即使没有结果,也返回单个MySql表中所有日期的数据

时间:2019-03-12 11:04:13

标签: php mysql

我只有一个数据表(以下简化)

| 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

或者,我尝试遍历所有产品,然后分别遍历日期,但是如果表中没有日期,则不会再返回任何数据,因此我的表会偏斜。

我已经看到其他人将日期存储在另一个表中,然后遍历该表,这感觉有点过头了,因为我在该表中拥有所有日期,因此我尝试将表连接到自身上,但这也不起作用。

在此先感谢您的帮助。

1 个答案:

答案 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