如何填补每周数据的空白?

时间:2013-02-19 11:36:41

标签: mysql

我有一个包含4个字段的表(id,Year,Week,Totals)。

我需要一个查询,我想使用join,根据年份和周字段填充零值。

在我的例子中,我需要填写第3周和第4周/年的零值

Rec Id, Year, Week, Totals
1, '2012', '52', '23'
2, '2013', '1' , '9'
3, '2013', '2' , '4'

Missing record from DB -> null, '2013', '3' , '0'
Missing record from DB -> null, '2013', '4' , '0'

4, '2013', '5' , '5'
5, '2013', '6' , '6'
6, '2013', '7' , '5'

1 个答案:

答案 0 :(得分:1)

这是一个有趣的!好的,我们走了。首先,我会给你一个简单的版本,它依赖于几个假设:

  1. 您的表格中每年至少有一个条目
  2. 在任何特定年份,您的表中每周至少有一次。 IE:此查询返回从1到52的所有数字:

    从您的__table中选择DISTINCT周

  3. 鉴于这些限制,此查询应该按您的要求执行:

    INSERT INTO your_table (id, year, week, totals)
        SELECT null, y, w, 0 FROM (
            SELECT DISTINCT week w FROM your_table
        ) weeks
        CROSS JOIN 
        (
            SELECT DISTINCT year y FROM your_table
        ) years
        WHERE
            (y > (select min(year) from your_table) OR w > (select min(week) from your_table where `year`=y))
            AND
            (y < (select max(year) from your_table) OR w < (select max(week) from your_table where `year`=y))
            AND 
            NOT EXISTS (select year, week from your_table where `year`=y AND `week`=w)
    

    如果条件2可能不满意 - 如果每年都缺少一些周,则可以替换此行

    SELECT DISTINCT week w FROM your_table
    

    SELECT
        (TWO_1.SeqValue + TWO_2.SeqValue + TWO_4.SeqValue + TWO_8.SeqValue + TWO_16.SeqValue + TWO_32.SeqValue) w
    FROM
        (SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue) TWO_1
        CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 2 SeqValue) TWO_2
        CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 4 SeqValue) TWO_4
        CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 8 SeqValue) TWO_8
        CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 16 SeqValue) TWO_16
        CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 32 SeqValue) TWO_32
    HAVING w >= 1 AND w <= 52
    

    给出更一般的案例:

    INSERT INTO your_table (id, year, week, totals)
        SELECT null, y, w, 0 FROM (
            SELECT
                (TWO_1.SeqValue + TWO_2.SeqValue + TWO_4.SeqValue + TWO_8.SeqValue + TWO_16.SeqValue + TWO_32.SeqValue) w
            FROM
                (SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue) TWO_1
                CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 2 SeqValue) TWO_2
                CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 4 SeqValue) TWO_4
                CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 8 SeqValue) TWO_8
                CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 16 SeqValue) TWO_16
                CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 32 SeqValue) TWO_32
            HAVING w >= 1 AND w <= 52
        ) weeks
        CROSS JOIN 
        (
            SELECT DISTINCT year y FROM your_table
        ) years
        WHERE
            (y > (select min(year) from your_table) OR w > (select min(week) from your_table where `year`=y))
            AND
            (y < (select max(year) from your_table) OR w < (select max(week) from your_table where `year`=y))
            AND 
            NOT EXISTS (select year, week from your_table where `year`=y AND `week`=w)
    

    (如果不满足条件1,你可以使用类似的技术来生成年份列表,但我猜你没有完整的年度漏洞。)

    最后,如果你有一年和一周的唯一索引,这可以简化一点。如果您还没有这样的索引,可以像这样创建它:

    ALTER TABLE `your_table` ADD CONSTRAINT date UNIQUE (
    `year`,
    `week`
    )
    

    如果你愿意,你可以在完成后删除它,如下所示:

    ALTER TABLE `your_table` DROP INDEX date;
    

    在这种情况下,可以删除where子句的最后一部分:

    AND 
    NOT EXISTS (select year, week from your_table where `year`=y AND `week`=w)
    

    因为INSERT IGNORE将跳过已存在该唯一年/周组合的任何行。

    对范围生成代码的答案赞不绝口:https://stackoverflow.com/a/8349837/160565