我有一个像这样的表格方案:
CREATE TABLE MyEvents
(
Id INT PRIMARY KEY NOT NULL,
Name NVARCHAR(MAX) NOT NULL
);
CREATE TABLE MyEventSchedules
(
Id INT PRIMARY KEY NOT NULL,
MyEventId INT NOT NULL,
StartDate BIGINT NOT NULL,
TimeOfDay BIGINT NOT NULL,
Interval BIGINT NOT NULL
);
数据如:
INSERT INTO MyEvents (Id, Name)
VALUES (1, 'Event #1');
-- StartDate: new DateTime(2016, 5, 1), TimeOfDay: 16:00 - repeats every 3 day
INSERT INTO MyEventSchedules (Id, MyEventId, StartDate, TimeOfDay, Interval)
VALUES (1, 1, 635976576000000000, 576000000000, 2592000000000);
-- StartDate: new DateTime(2016, 5, 15), TimeOfDay: 12:00 - repeats every 30 day
INSERT INTO MyEventSchedules (Id, MyEventId, StartDate, TimeOfDay, Interval)
VALUES (2, 1, 635988672000000000, 432000000000, 25920000000000);
INSERT INTO MyEvents (Id, Name)
VALUES (2, 'Event #2');
-- StartDate: new DateTime(2016, 5, 2), TimeOfDay: 14:00 - repeats every day
INSERT INTO MyEventSchedules (Id, MyEventId, StartDate, TimeOfDay, Interval)
VALUES (3, 2, 635977440000000000, 504000000000, 864000000000);
INSERT INTO MyEvents (Id, Name)
VALUES (3, 'Event #3');
-- StartDate: new DateTime(2016, 5, 2), TimeOfDay: 22:00 - repeats every day
INSERT INTO MyEventSchedules (Id, MyEventId, StartDate, TimeOfDay, Interval)
VALUES (4, 3, 635977440000000000, 792000000000, 864000000000);
INSERT INTO MyEvents (Id, Name)
VALUES (4, 'Event #4');
-- StartDate: new DateTime(2016, 5, 2), TimeOfDay: 18:00 - repeats every day
INSERT INTO MyEventSchedules (Id, MyEventId, StartDate, TimeOfDay, Interval)
VALUES (5, 4, 635977440000000000, 648000000000, 864000000000);
BIGINT
用于将时间戳存储为数字(https://msdn.microsoft.com/da-dk/library/system.datetime.ticks(v=vs.110).aspx)。像Unix时间戳一样。
我想SELECT
最接近时间戳的事件,但我无法弄清楚如何做到这一点。我想出了这个,但我不确定它是否是正确的方式。
你可以说我希望通过它的时间表找到下一个事件的时间
DECLARE @CurrentTime BIGINT = 635979600000000000; -- new DateTime(2016, 5, 4, 12, 0, 0).Ticks
SELECT *
FROM MyEvents
JOIN MyEventSchedules ON (MyEventSchedules.MyEventId = MyEvents.Id)
OUTER APPLY (
SELECT
((@CurrentTime - x.StartDate) / x.Interval) AS NumberOfTimesRepeated,
((((@CurrentTime - x.StartDate) / x.Interval) * x.Interval)) AS test,
(@CurrentTime - ((@CurrentTime - x.StartDate) / x.Interval)) Value
FROM MyEventSchedules x
WHERE x.MyEventId = MyEvents.Id) as Sort
ORDER BY Sort.Value
这里我有一些测试用例;
SELECT MyEvents.Id
FROM MyEvents
JOIN MyEventSchedules ON (MyEventSchedules.MyEventId = MyEvents.Id)
-- ORDER BY "closest to @CurrentTime"
-- Expected (1, 2, 4, 3)
DECLARE @CurrentTime BIGINT = 635978052000000000; -- new DateTime(2016, 5, 2, 17, 0 , 0).Ticks
SELECT MyEvents.Id
FROM MyEvents
JOIN MyEventSchedules ON (MyEventSchedules.MyEventId = MyEvents.Id)
-- ORDER BY "closest to @CurrentTime"
-- Expected (4, 3, 2, 1)
DECLARE @CurrentTime BIGINT = 635989068000000000; -- new DateTime(2016, 5, 15, 11, 0, 0).Ticks
SELECT MyEvents.Id
FROM MyEvents
JOIN MyEventSchedules ON (MyEventSchedules.MyEventId = MyEvents.Id)
-- ORDER BY "closest to @CurrentTime"
-- Expected (1, 2, 4, 3)
答案 0 :(得分:1)
declare @MyEventSchedules table
(
ID INT IDENTITY(1,1) PRIMARY KEY,
MyEventId INT,
StartDateAndTime DATETIME,
Interval TINYINT /* days, I suppose */
)
declare @CurrentTime datetime = GETDATE()
insert into @MyEventSchedules(MyEventId, StartDateAndTime, Interval)
values
(1, '20161102 16:00', 3),
(1, '20161116 12:00', 30),
(1, '20161112 01:00', 30),
(2, '20160502 14:00', 1),
(3, '20160502 22:00', 1)
;with cteEvents as
(
select distinct e.MyEventID from @MyEventSchedules e
),
cteSched as
(
select
s.MyEventID,
s.StartDateAndTime,
s.Interval,
s.Interval * CAST(DATEDIFF(DD, s.StartDateAndTime, @CurrentTime) / s.Interval AS INT) IntervalDiff
from @MyEventSchedules s
where s.StartDateAndTime <= @CurrentTime
)
select *
from cteEvents e
outer apply
(
select top (1)
--s.IntervalDiff,
CASE
WHEN DATEADD(DD, s.IntervalDiff, s.StartDateAndTime) < @CurrentTime
THEN DATEADD(DD, s.IntervalDiff + s.Interval, s.StartDateAndTime)
ELSE DATEADD(DD, s.IntervalDiff, s.StartDateAndTime)
END NextRun
from cteSched s
where s.MyEventID = e.MyEventID
order by NextRun ASC
) s
答案 1 :(得分:0)
经过大量的反复试验后,我找到了正确的数学运算来进行查询。
DECLARE @CurrentTime BIGINT = 635978772000000000;
SELECT MyEvents.*, Sort.*, Sort.Value / 864000000000 AS DaysToNext, Sort.Value / 36000000000 AS HourstoNext FROM MyEvents
OUTER APPLY (
SELECT
CASE WHEN MIN(x.StartDate + x.TimeOfDay + ((((@CurrentTime - x.StartDate) / x.Interval)) * x.Interval) - @CurrentTime) < 0
THEN MIN(x.StartDate + x.TimeOfDay + ((((@CurrentTime - x.StartDate) / x.Interval)+1) * x.Interval) - @CurrentTime)
ELSE MIN(x.StartDate + x.TimeOfDay + ((((@CurrentTime - x.StartDate) / x.Interval)) * x.Interval) - @CurrentTime)
END
as Value
FROM
MyEventSchedules x
WHERE x.MyEventId = MyEvents.Id AND x.StartDate <= @CurrentTime
) Sort
WHERE Sort.Value IS NOT NULL
ORDER BY Sort.Value