sql - TSQL:查找上一个“星期几”逻辑的日期。是否有任何边缘情况会失败并且可以简化吗?
问题描述
我有各种 SSIS 作业,它们将在一周中的不同日子运行,并且需要参考之前的作业在运行之前是否已经运行(通过日志表时间戳)。由于每种作业类型都有不同的时间表(取决于第 3 方集成需求),我希望有一个通用脚本来设置一些变量,这些变量可以根据需要在每个脚本中选择性地引用。
例如,“每隔一个星期三,‘作业 A’ 运行,每隔一个星期三交错运行,‘作业 B’ 运行。如果‘作业 A’没有运行,我不需要运行‘作业 B’(留下日志时间戳运行时间)上周三。”
所以,我搜索了许多不同的方法,下面是我想出的:
-- Sets the first day of the week to Monday (used in finding 'previous day' below)
SET DATEFIRST 1
DECLARE
@DATE_TIME SMALLDATETIME
, @LastWeekMon SMALLDATETIME
, @LastWeekTue SMALLDATETIME
, @LastWeekWed SMALLDATETIME
, @LastWeekThu SMALLDATETIME
, @LastWeekFri SMALLDATETIME
, @LastWeekSat SMALLDATETIME
, @LastWeekSun SMALLDATETIME
, @PrevMon SMALLDATETIME
, @PrevTue SMALLDATETIME
, @PrevWed SMALLDATETIME
, @PrevThu SMALLDATETIME
, @PrevFri SMALLDATETIME
, @PrevSat SMALLDATETIME
, @PrevSun SMALLDATETIME
, @DontAllowPrevToBeToday BIT
, @DAY_SPECIFIC_ADJUST INT
--SET CONSTANTS
--SET @DATE_TIME = GETDATE();
SET @DATE_TIME = '2018-07-21 00:00:00';
SET @DontAllowPrevToBeToday = 1; --true
select @DATE_TIME as DATE_TIME
-----------------------------------------
--GET LAST WEEK'S DAY-OF-THE-WEEK DATE (REGARDLESS OF SYSTEM ZERO DATE AND DATEFIRST SETTINGS)
SELECT @LastWeekMon = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-25T00:00:00') --12/25/1899 is a Monday
SELECT @LastWeekTue = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-26T00:00:00') --12/26/1899 is a Tuesday
SELECT @LastWeekWed = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-27T00:00:00') --12/27/1899 is a Wednesday
SELECT @LastWeekThu = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-28T00:00:00') --12/28/1899 is a Thursday
SELECT @LastWeekFri = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-29T00:00:00') --12/29/1899 is a Friday
SELECT @LastWeekSat = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-30T00:00:00') --12/30/1899 is a Saturday
SELECT @LastWeekSun = DATEADD(week,
DATEDIFF(week,'19000101',@DATE_TIME),'1899-12-31T00:00:00') --12/31/1899 is a Sunday
SELECT @LastWeekMon as LastWeekMon, @LastWeekTue as LastWeekTue, @LastWeekWed as LastWeekWed, @LastWeekThu as LastWeekThu, @LastWeekFri as LastWeekFri, @LastWeekSat as LastWeekSat, @LastWeekSun as LastWeekSun
-----------------------------------------
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(0); --Mon + 0 = 1 = Monday
SELECT @PrevMon =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekMon
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(1); --Mon + 1 = 2 = Tuesday
SELECT @PrevTue =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekTue
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(2); --Mon + 2 = 3 = Wednesday
SELECT @PrevWed =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekWed
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(3); --Mon + 3 = 4 = Thursday
SELECT @PrevThu =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekThu
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(4); --Mon + 4 = 5 = Friday
SELECT @PrevFri =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekFri
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(5); --Mon + 5 = 6 = Saturday
SELECT @PrevSat =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekSat
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SET @DAY_SPECIFIC_ADJUST = DATEDIFF(day, 0, @DATE_TIME) + -(6); --Mon + 6 = 7 = Sunday
SELECT @PrevSun =
CASE
WHEN @DontAllowPrevToBeToday = 1 And DATEDIFF(day, 0, @DATE_TIME) = DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0) THEN
--PREV DAY IS TODAY, USE DAY FROM LAST WEEK
@LastWeekSun
ELSE
--PREV DAY SELECT
DATEADD(day, DATEDIFF(day, 0, @DATE_TIME - (@DAY_SPECIFIC_ADJUST) %7), 0)
END
SELECT @PrevMon as PrevMon, @PrevTue as PrevTue, @PrevWed as PrevWed, @PrevThu as PrevThu, @PrevFri as PrevFri, @PrevSat as PrevSat, @PrevSun as PrevSun
这是声音吗?有没有更简单的方法来实现这一点?我确信必须有,但我很难过。
感谢您的帮助和反馈!
解决方案
免责声明 这本质上是一个很长的评论,但作为答案发布,因为它涉及大量的代码和评论。
来自@deeg的 How to get last run job details in SQL。
SELECT t2.instance_id
,t1.name as JobName
,t2.step_id as StepID
,t2.step_name as StepName
,CONVERT(CHAR(10), CAST(STR(t2.run_date,8, 0) AS DATETIME), 111) as RunDate
,STUFF(STUFF(RIGHT('000000' + CAST ( t2.run_time AS VARCHAR(6 ) ) ,6),5,0,':'),3,0,':') as RunTime
,t2.run_duration
,CASE t2.run_status WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Cancelled'
WHEN 4 THEN 'In Progress'
END as ExecutionStatus
,t2.message as MessageGenerated
FROM msdb.dbo.sysjobs t1
JOIN msdb.dbo.sysjobhistory t2
ON t1.job_id = t2.job_id
--Join to pull most recent job activity per job, not job step
JOIN (
SELECT TOP 1
t1.job_id
,t1.start_execution_date
,t1.stop_execution_date
FROM msdb.dbo.sysjobactivity t1
--If no job_id detected, return last run job
ORDER
BY last_executed_step_date DESC
) t3
--Filter on the most recent job_id
ON t1.job_id = t3.job_Id
--Filter out job steps that do not fall between start_execution_date and stop_execution_date
AND CONVERT(DATETIME, CONVERT(CHAR(8), t2.run_date, 112) + ' '
+ STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), t2.run_time), 6), 5, 0, ':'), 3, 0, ':'), 121)
BETWEEN t3.start_execution_date AND t3.stop_execution_date
将为您提供在开始和停止执行日期之间运行的所有作业(根据需要更改)。如果作业 A成功,则 RunDate(和/或 RunTime)之间的日期差异在 7 天内。然后运行作业 B。
aka... where t2.JobName = 'yourjob'
and t2.run_status = 1
,然后运行 Job B。
这种逻辑会有帮助吗?请注意,如有必要,您可以过滤掉返回的内容以摆脱各个步骤。
推荐阅读
- python - 如何给从 0 开始的唯一整数 id 到随机给定数字?
- testing - 在 testcafe 的相同测试执行期间,如何使用与 Json 中写入的相同值
- r - R函数ifelse仅返回最后一行的评估
- terminal - PyCharm 终端:目录的奇怪背景颜色
- c# - 无法在 Windows 启动 Wpf 时打开数据库
- intellij-idea - 我试图进行突变测试。在 Intellij 的想法中,我使用了 ptest。但是我收到一条错误消息,提示无法创建 HTML 文件
- excel - 不同单元格中每个循环值的输出
- apache-spark - Spark - 使用 HEADER 和 TRAIL 行读取 CSV 文件......如何忽略它们?
- javascript - 如何重新实例化由 javascript (Nashorn Engine) 实例化的类
- vba - 如何将字符串转换为 msoLanguageID