【问题标题】:Complicated sql date logic: How can I schedule my reports?复杂的 sql 日期逻辑:如何安排我的报告?
【发布时间】:2023-03-09 06:25:01
【问题描述】:

我有一个看起来像这样的表(简化):

*ScheduledReports*
ReportID  
StartDate  
Frequency  
Interval (1=months, 2=days)

因此,如果我想每 3 天运行一次报告,频率为 3,间隔为 2。

我正在尝试编写一个我们可以每天运行一次的存储过程,它将运行表中为今天安排的所有报告(或者自我们上次运行存储过程以来应该已经运行)。

存储过程还可以访问 lastRunTime(此存储过程的最后一次运行时间)。

这是我的查询到目前为止的样子:

-- get monthly reports that should be run
SELECT reportID
FROM ScheduledReports
WHERE intervalType = 1 AND
    dateadd(m,  (
           frequency * ceiling((
              --sql server calculates datediff of months based on the actual int of the month
              --not if it's a true month later, so the following is necessary to check for
              --a dayOfMonth difference
              CASE
                  WHEN startDate > @lastRunTime
                         THEN 0
                  WHEN day(startDate) > day(@lastRunTime)
                         THEN datediff(m, startDate, @lastRunTime) - 1
                  ELSE datediff(m, startDate, @lastRunTime)
                  END
              ) / (frequency*1.0))
           ), startDate) BETWEEN @lastRunTime AND getDate()

UNION ALL

-- get weekly reports that should be run 
SELECT reportID
FROM ScheduledReports
WHERE intervalType = 2 AND
    dateadd(d, (
           frequency * ceiling((
              CASE
                  WHEN startDate > @lastRunTime
                         THEN 0
                  ELSE datediff(d, startDate, @lastRunTime)
                  END
              ) / (frequency*1.0)
           )), startDate) BETWEEN @lastRunTime AND getDate()

不过,逻辑有些不对劲。我的逻辑有什么问题?我怎样才能做到这一点?

【问题讨论】:

  • 如果上次生成报告的时间超过一天怎么办?
  • @mark bannister - 如果它应该在上次运行和今天之间的任何时间发送,我们希望发送一次
  • 让您创建另一个表的解决方案是否可以接受?还是您受限于仅使用您目前拥有的东西?

标签: sql sql-server tsql logic


【解决方案1】:

存储过程还可以访问 lastRunTime(此存储过程的最后一次运行时间)。

您不需要知道上次生成每份报告的时间吗?而不是最后一次运行这个存储过程?每次运行存储过程时,可能会或可能不会生成每个报告。为了知道每个报告的间隔是否已经过去(3 天、1 个月等),您需要知道上次生成该报告的时间。

如果您将 LastReportRun 日期列添加到表中会怎样。然后不要针对 @lastRunTime 测试今天的日期,而是针对 LastReportRun。

Report Run Today; Today = 2012/04/15

ID  StartDate   Freqcy  Interval  LastReportRun
--  ----------  ------  --------  ----------------  
1    2000/01/01  1      Days      2012/04/14         1 day ago;    print it
2    2000/01/01  14     Days      2012/04/09         6 days ago;   don`t print it
3    2000/01/01  3      Months    2012/01/13         > 3 mos ago;  print it
4    2000/01/01  3      Months    2012/01/17         < 3 mos ago;  don`t print it

【讨论】:

  • 我希望它根据开始日期运行。因此,如果开始日期是 2011 年 12 月 1 日,并且频率和间隔是每个月,那么我希望它在 2012 年 1 月 1 日、2012 年 2 月 1 日等运行。如果我在 2/ 2/2012,最后运行日期是 1/31/2012,我应该能够弄清楚我需要今天运行它以弥补错过的 2/1/2012...
【解决方案2】:

我们设法修复了这个错误 - 我们应该在案例中添加 1,而不是减去,因为我们想要获得下一个运行日期,而不是前一个。将月份大小写更改为:

 CASE
        WHEN startDate > @lastRunTime
              THEN 0
        WHEN day(startDate) > day(@lastRunTime)
              THEN datediff(m, startDate, @lastRunTime)
        ELSE datediff(m, startDate, @lastRunTime) + 1
 END

以及当天的情况:

CASE
     WHEN startDate > @lastRunTime
        THEN 0
     ELSE datediff(d, startDate, @lastRunTime) + 1
END

现在它运行良好:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多