2

给定以下示例查询,当还给出一组要排除的范围时,考虑到这些范围可能有重叠的日期,什么是计算日期范围内总天数的合理且高效的方法?

更简单地说,我有一个表格,其中包含一组关闭计费的日期范围,我从一个日期范围开始(比如 Jan1 - Jan31),我需要确定在该范围内发生了多少计费天。只需将日期的日期差异减去禁用日期的日期差异的总和。但是,禁用日期范围有可能重叠,即在一条记录中禁用 Jan5-Jan8,在另一条记录中禁用 Jan7-Jan10 - 因此简单的总和会使 Jan7 加倍。排除这些重叠并获得准确计数的最佳方法是什么。

Declare @disableranges table (disableFrom datetime, disableTo datetime)
insert into @disableranges
select '01/05/2013', '01/08/2013' union
select '01/07/2013', '01/10/2013' union
select '01/15/2013', '01/20/2013'

declare @fromDate datetime = '01/01/2013'
declare @toDate datetime = '01/31/2013'

declare @totalDays int = DATEDIFF(day,@fromDate,@toDate)
declare @disabledDays int = (0 /*not sure best way to calc this*/)

select @totalDays - @disabledDays
4

2 回答 2

2

就我而言,尝试过这个并且工作正常。

Declare @disableranges table (disableFrom datetime, disableTo datetime)
insert into @disableranges
select '01/05/2013', '01/08/2013' union
select '01/07/2013', '01/10/2013' union
select '01/15/2013', '01/20/2013'

declare @fromDate datetime = '01/01/2013'
declare @toDate datetime = '01/31/2013'

declare @totalDays int = DATEDIFF(day,@fromDate,@toDate) + 1 /*Without +1 it is giving 30 instead of 31*/
declare @disabledDays int = (0 /*not sure best way to calc this*/)
/*Fill temporary table with the given date range.*/
SELECT  DATEADD(DAY, nbr - 1, @fromDate) TempDate INTO #Temp
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
          FROM      sys.columns c
        ) nbrs
WHERE   nbr - 1 <= DATEDIFF(DAY, @fromDate, @toDate)
/*Check how many dates exists in the disableranges table*/
SELECT @disabledDays=count(*) from #Temp t WHERE 
EXISTS(SELECT * FROM @disableranges 
WHERE t.TempDate BETWEEN disableFrom AND DATEADD(d, -1, disableTo))

select @totalDays /*Output:31*/
select @disabledDays /*Output:10*/
select @totalDays - @disabledDays /*Output:21*/
drop table #Temp

从答案https://stackoverflow.com/a/7825036/341117中获取帮助,用日期范围填写表格

于 2013-03-04T21:33:33.387 回答
2

您可以使用递归 CTE生成 和 之间的@dateFrom日期@dateTo。然后将日期与范围进行比较,并找到任何范围内的所有日期。最后,计算结果中的行数以获取禁用日期的计数(DEMO):

-- recursive CTE to generate dates
;with dates as (
  select @fromDate as date
  union all
  select dateadd(day, 1, date)
  from dates
  where date < @toDate
)

-- join with disable ranges to find dates in any range
, disabledDates as (
  select date from dates D
  left join @disableranges R
    on D.date >= R.disableFrom and d.Date < R.disableTo
  group by date
  having count(R.disablefrom) >= 1
)

-- count up the total disabled dates
select @disabledDays=count(*) from disabledDates;
于 2013-03-04T21:38:55.347 回答