遍历日期Mysql循环

时间:2019-04-20 21:05:56

标签: mysql loops stored-procedures

我编写了一个存储过程,要在三年内每周进行迭代。但是它不起作用,并返回模糊的错误消息。

  

#1064-您的SQL语法有错误;检查与您的MariaDB服务器版本相对应的手册以获取正确的语法,以在第18行的''附近使用

DELIMITER $$
CREATE PROCEDURE loop_three_years()
BEGIN
    declare y INT default 2016;
    declare m int default 4;
    declare d int default 20;
    WHILE y <= 2019 DO
        WHILE YEARWEEK(concat(y, '-', m, '-', d)) <= 53 DO
            WHILE m < 12 DO
                WHILE (m = 2 and d <= 29) OR (d <=30 and m in(4, 6,9,11)) OR ( m in(1,3,5,7,8,10,12) AND d <= 31) DO
                    set d = d + 7;
                    SELECT YEARWEEK(concat(y, '-', m, '-', d));
                END WHILE;
                set d=1;
        END WHILE;
        set m = 1;
        SET y = y + 1;
    END WHILE;
END
$$

当我将其用作最少的零件时,它们可以工作,所以我不确定重组的问题是什么。同样不确定是否有更好的方法可以做到这一点。 (select仅用于测试,当我使用真实代码时,它将是insert

1 个答案:

答案 0 :(得分:1)

Slightly Altered from a previous solution

您可以使用系统中的任何其他表来构建自己的动态日历/列表,该表至少具有与伪造行号所需的记录一样多的记录。下面的查询将使用MySQL @变量,其作用类似于内联程序和声明。我可以从给定的日期开始列表...例如您的2016-04-20,然后每次迭代,使用基于日期的函数添加1周。无需我知道或关心28、29(le年),30或31天有多少天。

“ AnyTableThatHasAtLeast156Records”下面的表引用就是这样。数据库中任何具有至少156条记录(每年52周,每年3年)的表

select
      YEARWEEK( @startDate ) WeekNum,
      @startDate as StartOfWeek,              
      @startDate := date_add( @startDate, interval 1 week ) EndOfWeek
   from 
      ( select @startDate := '2016-04-20') sqlv,
      AnyTableThatHasAtLeast156Records
   limit
      156 

这将为您提供156条记录的列表(假设您的“ anyTable…”一次具有全部156条记录。如果您需要将其连接到其他事务表,则可以通过创建上面的JOIN表来实现。在这里受益,因为我包括了开始日期和星期几,所以这些可以成为您加入表格的一部分。

示例,在

record   WeekNum   StartOfWeek   EndOfWeek
1        ??        2016-04-20    2016-04-27
2        ??        2016-04-27    2016-05-04
3        ??        2016-05-04    2016-05-11
4        ??        2016-04-11    2016-05-18... etc

通过将1周添加到起点,您可以看到它将执行例:星期一至星期一。下面的JOIN条件比EndOfWeek还少。这将说明截至TOUP的所有交易,但不包括结束日期...例如2016-04-26 11:59:59 PM的交易(因此,比2016-04-27少,因为04/27是该交易的开始下周的交易周期)

select
      Cal.WeekNum,
      YT.YourColumns
   from
      YourTransactionTable YT
         JOIN ( aboveCalendarQuery ) Cal
            on YT.TransactionDate >= Cal.StartOfWeek
            AND YT.TransactionDate < Cal.EndOfWeek
   where
      whatever else

如果您想要的话,甚至可以对分组依据(例如WeekNum)进行sum()。

希望这是一种构建日历以运行并链接到事务(如果需要)的更加准确和有效的方法。

回复评论。

您可以通过加入一个联接(选择1个联合选择2个联合...选择156),但是您可以选择。 “ AnyTable…”的唯一原因是,我敢肯定,使用任何具有事务处理的合理数据库,您都可以轻松拥有156条记录。唯一的目的是只允许一行在循环中循环以动态创建行。

比开始时遇到的循环机制还多得多的声音。没什么错,特别是学习目的,但是如果有更有效的方法,那更有意义吗?

每个来自评论的反馈

我不太清楚您要插入的另一个表,但是可以,您可以将其用于所有3000件事。提供更多您想做的事情,我可以进行调整...同时,类似这样的事情...

insert into YourOtherTable
(   someField,
    AnotherField,
    WeekNum 
)
select
      x.someField,
      x.AnotherField,
      z.WeekNum
   from
      Your3000ThingTable x
         JOIN (select
                     YEARWEEK( @startDate ) WeekNum,
                     @startDate as StartOfWeek,              
                     @startDate := date_add( @startDate, interval 1 week ) EndOfWeek
                  from 
                     ( select @startDate := '2016-04-20') sqlv,
                     AnyTableThatHasAtLeast156Records
                  limit
                     156 ) z
            on 1=1
   where
      x.SomeCodition...

通过加入1 = 1上的156条记录的选择(始终为true),它将为Your3000ThingTable中的任何记录返回156条记录。因此,如果您的库存项目表带有

Item  Name
1     Thing1
2     Thing2
3     Thing3

您的最终插入内容将是

Item   Name     WeekNum
1      Thing1   1
1      Thing1   2
1      Thing1   ...
1      Thing1   156
2      Thing2   1
2      Thing2   2
2      Thing2   ...
2      Thing2   156
3      Thing3   1
3      Thing3   2
3      Thing3   ...
3      Thing3   156

要预先确认会发生什么,只需在1 = 1上尝试选择/联接,您将看到查询将要插入到目标表中的所有记录。