使用上一行的值和分组进行UPDATE查询

时间:2013-08-13 15:10:44

标签: mysql sql-update self-join

我正在尝试更新每组商品代码的datedelta字段。 datedelta字段应包含自上次销售特定商品以来的天数。例如,我的表在更新之前看起来像这样:

表:'销售'

   id      date       datedelta    itemcode
  --------------------------------------------
    1    2012-09-01     null          1
    2    2012-09-08     null          1
    3    2012-09-20     null          1
    4    2012-03-01     null          2
    5    2013-06-01     null          3
    6    2013-06-06     null          3

更新后,我希望该表看起来像这样:

   id      date       datedelta    itemcode
  --------------------------------------------
    1    2012-09-01       0           1
    2    2012-09-08       7           1
    3    2012-09-20      12           1
    4    2012-03-01       0           2
    5    2013-06-01       0           3
    6    2013-06-06       5           3

我遇到以下方面的问题:

a)如何进行自我加入并参考上一个日期的记录,

b)如何处理分组部分。即日期差异仅针对相同的项目代码计算。

我尝试了以下查询但没有成功:

UPDATE sales AS s
INNER JOIN sales AS prev 
ON prev.id IN (SELECT t.id FROM sales WHERE MAX(t.saledate) < r.saledate GROUP BY itemcode ORDER BY itemcode) 
SET datedelta = IFNULL(DATEDIFF(r.saledate, p.saledate), 0)

2 个答案:

答案 0 :(得分:0)

虽然您可以通过连接执行此操作,但我发现使用相关子查询更容易:

UPDATE sales s
     set s.datedelta = coalesce(datediff((select sprev.racedate
                                          from sales sprev
                                          where sprev.itemcode = s.itemcode and
                                                sprev.racedate < s.racedate
                                          order by sprev.racedate desc
                                          limit 1
                                         ), rprev.racedate
                                        ), 0);

至于您的查询,至少有一个问题是与列一起使用的表别名与为表定义的别名不匹配。

答案 1 :(得分:0)

关于在连续记录中找到差距的问题,我发现使用游标迭代记录很有趣。我不认为它们经常在这里使用,但我认为它们比有时错综复杂的自我连接更容易包围。

CREATE PROCEDURE findgaps()
    BEGIN    

    DECLARE done INT DEFAULT FALSE;
    DECLARE idv, datedeltav, itemcodev, prev_itemcodev INT;
    DECLARE datev, prev_datev DATE;

    DECLARE cur CURSOR FOR SELECT id, date, datedelta, itemcode
                           FROM sales
                           ORDER BY itemcode ASC, date ASC;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;       

    read_loop: LOOP
        SET prev_datev = datev;
        SET prev_itemcodev = itemcodev;
        FETCH cur INTO idv, datev, datedeltav, itemcodev;   
        IF done THEN
            LEAVE read_loop;
        END IF;
        IF NOT itemcodev <=> prev_itemcodev THEN
           SET prev_datev = datev;
        END IF;
        UPDATE sales s
        SET s.datedelta = DATEDIFF(datev,prev_datev)
        WHERE s.id = idv;
    END LOOP;    

    CLOSE cur;  

    END;

我没有对此进行测试或调试,但这将大致适合您。