Reputation: 19
I have an XML that has multiple schedules. I need help to show from the current day (Example: Monday, 14:00:03) how many days or hours or minutes left until a specific schedule [Sched 1 AT] or [Sched 2 AT] time start and day [Sched 1 Weekdays] or [Sched 1 Weekdays] in a separate column [TimeLeft]. Schedules I have, run:
My XML is and the query:
create table MyTable (Roles XML)
insert into MyTable values
('<registered guid="{B40F5E54-21D0-4EDB-B636-B2F9EE30CCDE}">
<schedule tz="Local" start="2007-11-01 00:00:00">
<trigger type="MonthlyByWeek" exact="False" at="18:05:00" weeks="2" weekdays="6" description="Every 2nd Saturday" />
<trigger type="MonthlyByWeek" exact="False" at="00:05:00" weeks="2" weekdays="0" description="Every 2nd Sunday" />
<modifier type="Network" />
</schedule>
</registered>
<registered guid="{A4465325-926A-48FA-B11E-D6E486D76D93}">
<schedule tz="Local" start="2009-11-11 00:00:00">
<trigger type="Weekly" exact="True" at="00:05:00" frequency="1" weekdays="0" description="Weekly on Sunday" />
<trigger type="Weekly" exact="True" at="04:05:00" frequency="1" weekdays="0" description="Weekly on Sunday" />
<modifier type="Network" />
</schedule>
</registered>
<registered guid="{3DE26049-74E7-4FE3-9E47-CF022A6F7923}">
<schedule tz="Local" start="2011-11-11 00:00:00">
<trigger type="Weekly" exact="True" at="00:07:30" frequency="1" weekdays="1, 2, 3, 4, 5, 6" description="Daily" />
<modifier type="Network" />
</schedule>
</registered>')
SELECT T.Schedule.query('.') AS Schedule,
CASE
WHEN T.Schedule.value('(schedule/trigger/@type)[1]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE T.Schedule.value('(schedule/trigger/@type)[1]', 'nvarchar(100)')
END [Sched 1 When],
CASE
WHEN T.Schedule.value('(schedule/trigger/@at)[1]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE T.Schedule.value('(schedule/trigger/@at)[1]', 'nvarchar(100)')
END [Sched 1 AT],
-- Week Start Sunday
-- Sunday = 0
-- Monday = 1
-- Tuesday = 2
-- Wednesday = 3
-- Thursday = 4
-- Friday = 5
-- Saturday = 6
CASE
WHEN T.Schedule.value('(schedule/trigger/@frequency)[1]', 'nvarchar(100)') LIKE '%1%'
THEN 'Once'
WHEN T.Schedule.value('(schedule/trigger/@frequency)[1]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE 'Unknown'
END [Sched 1 Frequency],
CASE
WHEN T.Schedule.value('(schedule/trigger/@description)[1]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE T.Schedule.value('(schedule/trigger/@description)[1]', 'nvarchar(100)')
END [Sched 1 Description],
CASE
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[1]', 'nvarchar(100)') = '1, 2, 3, 4, 5, 6'
THEN 'Mon, Tue, Wend, Thu, Fri, Sat'
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[1]', 'nvarchar(100)') LIKE '%0%'
THEN 'Sun'
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[1]', 'nvarchar(100)') LIKE '%6%'
THEN 'Sat'
ELSE 'Unknown'
END [Sched 1 Weekdays],
CASE
WHEN T.Schedule.value('(schedule/trigger/@type)[2]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE T.Schedule.value('(schedule/trigger/@type)[2]', 'nvarchar(100)')
END [Sched 2 When],
CASE
WHEN T.Schedule.value('(schedule/trigger/@at)[2]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE T.Schedule.value('(schedule/trigger/@at)[2]', 'nvarchar(100)')
END [Sched 2 AT],
CASE
WHEN T.Schedule.value('(schedule/trigger/@frequency)[2]', 'nvarchar(100)') LIKE '%1%'
THEN 'Once'
WHEN T.Schedule.value('(schedule/trigger/@frequency)[2]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE 'Unknown'
END [Sched 2 Frequency],
CASE
WHEN T.Schedule.value('(schedule/trigger/@description)[2]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE T.Schedule.value('(schedule/trigger/@description)[2]', 'nvarchar(100)')
END [Sched 2 Description],
CASE
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[2]', 'nvarchar(100)') = '1, 2, 3, 4, 5, 6'
THEN 'Mon, Tue, Wend, Thu, Fri, Sat'
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[2]', 'nvarchar(100)') LIKE '%0%'
THEN 'Sun'
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[2]', 'nvarchar(100)') LIKE '%6%'
THEN 'Sat'
WHEN T.Schedule.value('(schedule/trigger/@weekdays)[2]', 'nvarchar(100)') IS NULL
THEN 'None'
ELSE 'Unknown'
END [Sched 2 Weekdays]
FROM
( SELECT CAST(Roles AS XML) as [State] from Mytable
) x
CROSS APPLY x.State.nodes('/registered') AS T(Schedule)
Upvotes: 0
Views: 88
Reputation: 6798
declare @checkdatetime datetime = '20200216 10:00:00';
select *, datediff(minute, @checkdatetime, o.execdatetime) as minutes_till_next_execution
from
(
select *,
row_number() over(partition by Scheduleguid, TrigAt /*?*/ order by execdatetime) as execrownum
from
(
select
sch.*,
--possible execution datetime
dateadd(day, d.n,
dateadd(month, isnull(m.n, 0),
--datetimefromparts(.....)
cast(cast(year(@checkdatetime) as varchar(20)) + right('00'+cast(month(@checkdatetime) as varchar(20)), 2) + '01 ' + TrigAt as datetime)
)) as execdatetime
from
--shred xml
(
select
T.Schedule.value('(@guid)[1]', 'uniqueidentifier') AS Scheduleguid,
dense_rank() over(order by T.Schedule) as ScheduleOrdinal, --position
S.Trig.value('(@type)[1]', 'nvarchar(100)') as TrigType,
S.Trig.value('(@at)[1]', 'nvarchar(100)') as TrigAt,
S.Trig.value('(@weeks)[1]', 'tinyint') as MonthWeekFrequency,
S.Trig.value('(@frequency)[1]', 'tinyint') as TrigFrequency,
S.Trig.value('(@description)[1]', 'nvarchar(100)') as TrigDescription,
S.Trig.value('(@weekdays)[1]', 'varchar(20)') as TrigWeekdays,
cast(ltrim(rtrim(ss.value)) as tinyint) as triggerweekday
FROM Mytable as x
cross apply x.Roles.nodes('./registered[position() <= 100]') AS T(Schedule) --position() to filter schedules in xml (first 2, 3, 100 schedules etc)
cross apply T.Schedule.nodes('./schedule/trigger') AS S(Trig)
cross apply string_split(S.Trig.value('(@weekdays)[1]', 'varchar(20)'), ',') as ss --split weekdays of trigger
) as sch
--lazy brute force
--days
cross apply
(
--31 values for days in a month
select top (31) row_number() over(order by (select null)) as n
from
(values(0), (0), (0), (0), (0), (0)) as num1(n)
cross join
(values(0), (0), (0), (0), (0), (0)) as num2(n)
) as d
--months
outer apply
(
--2 values for current and next month
select n
from (values(0), (1)) as num(n)
where sch.MonthWeekFrequency is not null
) as m
) as ex
where 1=1
-- execution dates which are eq or greater than @check
and @checkdatetime <= ex.execdatetime
-- execution dates of the same trigweekday
and ex.triggerweekday = datepart(weekday, dateadd(day, @@datefirst, ex.execdatetime))-1
--execution dates on the same week number
and
(
ex.MonthWeekFrequency is null
or
ex.MonthWeekFrequency = datediff(week, dateadd(month, datediff(month, '20200101', ex.execdatetime), '20200101'), ex.execdatetime) +1
)
) as o
where o.execrownum = 1 --...the very next execution
order by ScheduleOrdinal, TrigAt;
Upvotes: 1