我有一个表(SYS_Holidays),它有每个假期的开始和结束日期。我需要以关系形式输出所有假日日期。例如,我在2017年12月25日到2018年1月2日作为输入中的一行,我想输出25-Dec,26-Dec ...到2月1日为9行。
我写过这个剧本,请你告诉我如何才能提高效率?
SELECT
H.HolidayName
, DATEADD(DAY, Number-1, H.StartDate) AS HolidayDate
FROM
SYS_Holidays AS H
CROSS JOIN Config_Numbers AS N
WHERE
-- Figure the # of days between start and end: one row for each holiday-date
-- If EndDate is null, just use StartDate (i.e. 1-day holiday)
N.Number <= DATEDIFF(DAY, H.StartDate, ISNULL(H.EndDate, H.StartDate) ) + 1
注意:Config_Numbers是我用巨大整数列表创建的表(如BIGINT)
答案 0 :(得分:1)
可以使用日期表和内部联接来完成。如果子表不够高效,请使用子查询来创建表:
Create table #Test (HolidayName nvarchar(100), StartDate Date, EndDate Date)
Insert Into #Test Values ('Christmas', '2017-12-22', '2018-01-03'), ('Easter' , '2017-04-10', '2017-04-16')
SELECT HolidayName, DatesList.[Date] as HolidayDate
FROM #Test t
inner join (
SELECT cast(dateadd(day, number, '2017-1-1') as date) as [Date]
FROM master..spt_values WHERE type='P' AND number < 1000) AS DatesList
on t.StartDate<=DatesList.[Date] and t.EndDate>=DatesList.[Date]
答案 1 :(得分:0)
我修改了@ cloudsafe的答案,以产生下面的代码。它仍然 比使用Config_Numbers
的任何联接更快。子树的成本达到了0.2785。
我认为2048可以覆盖5年多一点,所以我把我的代码分成了5年的块,然后让UNION加入他们。
麻烦的是,我必须记住每隔5年再做一次UNION: - (
SELECT HolidayName, DatesList.[Date] as HolidayDate
FROM SYS_Holidays AS H
inner join (
SELECT cast(dateadd(day, number, '2013-01-01') as date) as [Date]
FROM master..spt_values WHERE type='P' AND number < 2048) AS DatesList
on H.StartDate <= DatesList.[Date] and H.EndDate >=DatesList.[Date]
UNION
SELECT HolidayName, DatesList.[Date] as HolidayDate, H.HolidayId, H.CampusId, H.CategoryId
FROM SYS_Holidays AS H
inner join (
SELECT cast(dateadd(day, number, '2018-01-01') as date) as [Date]
FROM master..spt_values WHERE type='P' AND number < 2048) AS DatesList
on H.StartDate <= DatesList.[Date] and H.EndDate >=DatesList.[Date]
还有其他改进建议吗?