Хорошо, я не проверял это, но я думаю, что наиболее эффективный способ сделать это - через таблицу подсчета, которую в любом случае полезно иметь в БД:
IF EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[num_seq]') AND type in (N'U'))
DROP TABLE [dbo].[num_seq];
SELECT TOP 100000 IDENTITY(int,1,1) AS n
INTO num_seq
FROM MASTER..spt_values a, MASTER..spt_values b;
CREATE UNIQUE CLUSTERED INDEX idx_1 ON num_seq(n);
Вы можетезатем используйте это, чтобы построить диапазон дат между двумя датами.Это быстро, потому что он просто использует индекс (на самом деле часто быстрее, чем цикл, так что я вынужден поверить)
create procedure getDates
@eventId int
AS
begin
declare @startdate datetime
declare @enddate datetime
--- get the start and end date, plus the start of the month with the start date in
select @startdate=startdate,
@enddate=enddate
from events where eventId=@eventId
select
@startdate+n AS date,
from
dbo.num_seq tally
where
tally.n<datediff(@monthstart, @enddate) and
Datepart(dd,@startdate+n) between 15 and 21 and
Datepart(dw, @startdate+n) = '<day>'
Помимо получения даты начала и окончания, третий x id каждый месяц долженбыть между 15-м и 21-м включительно.Имена дней в этом диапазоне должны быть уникальными, поэтому мы можем сразу их найти.
Если вы хотели получить второе имя дня, просто измените диапазон соответствующим образом или используйте параметр для его вычисления.
Он создает таблицу дат с использованием начальной даты, а затем добавляет дни (через список чисел в таблице подсчета), пока не достигнет конечной даты.
Надеюсь, это поможет!