2

次のクエリ例では、除外する範囲のセットも指定されている場合、それらの範囲の日付が重複している可能性がある場合、日付範囲の合計日数をカウントするための適切でパフォーマンスの高いアプローチは何ですか?

もっと簡単に言えば、請求がオフになっている一連の日付範囲のテーブルがあり、日付範囲(たとえば、Jan1〜Jan31)から始めて、その範囲で発生した請求可能な日数を判別する必要があります。単に日の日付の差から障害のある日の日付の合計を引いたものです。ただし、無効な日付範囲が重複する可能性があります。つまり、あるレコードではJan5-Jan8が無効になり、別のレコードではJan7-Jan10が無効になります。したがって、単純な合計ではJan7が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)
declare @disabledDays int = (0 /*not sure best way to calc this*/)

select @totalDays - @disabledDays
4

2 に答える 2

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 に答える
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 に答える