【问题标题】:Iterate Over Date Mysql Loop迭代日期 Mysql 循环
【发布时间】:2019-09-10 15:53:41
【问题描述】:

我已经编写了一个存储过程来每周迭代三年。但它不起作用并返回一个模糊的错误消息。

#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

【问题讨论】:

  • 看起来很奇怪,但你想做什么。它看起来像是从 2016-04-20 开始构建一个为期 3 年的 Y-M-D 日历,并随着您一次跳过 7 天而每周递增。

标签: mysql loops stored-procedures


【解决方案1】:

Slightly Altered from a previous solution

您可以使用系统中的任何其他表来构建自己的动态日历/列表,该表至少包含与伪造行号一样多的记录。下面的查询将使用 MySQL @ 变量,其工作方式类似于内联程序和声明。我可以从给定日期开始列表...例如您的 2016-04-20,然后每次迭代,使用基于日期的函数添加 1 周。我无需知道或关心 28、29(闰年)、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 周添加到起点,您可以看到它会执行 Ex: Monday to Monday。下面的 JOIN 条件比 EndOfWeek 少。这将解释 UP TO 但不包括结束日期的任何交易......例如 2016-04-26 11:59:59PM 的交易(因此少于 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

如果这是你想要的,你甚至可以用 group by 比如 by WeekNum 做 sum()。

希望这是一种更准确、更有效的方式来构建您的日历,以便在需要时与交易一起运行并链接到交易。

评论回复。

您可以通过加入 a (select 1 union select 2 union ... select 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 条记录的选择(始终为真),它将为 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 上的选择/连接,您就会看到查询将插入到目标表中的所有记录。

【讨论】:

  • 是的,这行得通。但是没有AnyTableThatHasAtLeast156Records 表就没有办法吗?
  • @user3783243,根据您的评论/问题修改答案。
  • 我需要选择所有 156 个日期范围 3000 次。 union all 在每个 select 上推进 startDate。这将用作insert into select YEARWEEK(@startDate) from mytablewith3000records。这是可能的还是需要循环方法?
  • @user3783243,修改了我的答案,请进一步查看底部以进行澄清。是的,您可以从选择/加入中插入
猜你喜欢
  • 2017-12-14
  • 2013-03-20
  • 1970-01-01
  • 2023-01-10
  • 2020-11-25
  • 2020-09-20
  • 1970-01-01
  • 1970-01-01
  • 2020-05-05
相关资源
最近更新 更多