1

[Date]日付形式で3列の「休日」テーブルを作成しました。これは[BusinessDay]、Y / Nであり[NameofDay] varchar(50)、休日または週末用です。土曜日、日曜日、クリスマスはすべて次の10年に向けてマークされています。

私が今やらなければならないことは、営業日を数えずに、リクエストを完了する必要がある日付を決定する方法を理解することです。読んだり読んだり読んだりしましたが、役に立ったものは何もありません。それは私の頭の中でいつも簡単です。

私が解決しようとしていること:リクエストが「優先」の場合はリクエスト[DueDate]の日付から10営業日、[TransactionDate]「クリティカル」の場合は5営業日で期限はどうなりますか。

4

3 に答える 3

4

@Andomar が提起した問題の再帰的な性質のため、別の回答を提案しています (これはたまたまはるかに単純ですが、ウィンドウ機能を利用できる必要があります)。これは、 より後の有効な営業日をカレンダーから結合し、TransactionDate要求ごとidに必要に応じて 5 行目または 10 行目を見つけます。

;WITH cte AS
(
   SELECT *,
         ROW_NUMBER() OVER (PARTITION BY id ORDER BY validDeliveryDate ASC) AS rn
   FROM (
       SELECT requests.*, holiday.Date as validDeliveryDate
       FROM requests
       JOIN holiday
         ON requests.TransactionDate < holiday.Date
         AND DATEADD(day, 25, requests.TransactionDate) >= holiday.Date
         AND holiday.BusinessDay = 'Y' ) v
)
SELECT *
FROM cte
WHERE rn = CASE WHEN critical = 1 THEN 5 ELSE 10 END

反復は必要ありません -ここで sqlfiddle を動作させます

于 2013-01-03T17:04:35.777 に答える
1

営業日の計算には繰り返しが必要です。日数を加算してから、非営業日を減算してから、再度加算します。

これを行う 1 つの方法は、ユーザー定義関数です。

if exists (select * from sys.objects where name ='WorkingDaysFrom' and type = 'FN')
    drop function dbo.WorkingDaysFrom
go
create function dbo.WorkingDaysFrom(
        @date date
,       @days int)
returns date
as
begin
        declare @result date = @date
        declare @remaining int = @days
        while @remaining > 0
                begin
                set     @result = dateadd(day, @remaining, @result)
                select  @remaining = count(*) 
                from    dbo.Holiday 
                where   [Date] between dateadd(day, 1-@remaining, @result) and @result
                        and BusinessDay = 'N'
                end
        return @result
end
go

SQL Fiddle での実例。 これは以下を出力します:

TransactionDate   Priority    DueDate
2013-01-01        Priority    2013-01-16
2013-01-01        Critical    2013-01-09
2013-01-03        Priority    2013-01-17
2013-01-03        Critical    2013-01-10
2013-01-06        Priority    2013-01-18
2013-01-06        Critical    2013-01-11
于 2013-01-03T17:24:09.717 に答える
0

私は次の作品だと思います:

select t.*
from (select t.*,
             row_number() over (partition by r.requestid, IsWorkDay order by seqdate) as WorkDayNum
      from (select r.requestid, r.TransactionDate,
                   (case when critical = 1 then 5 else 10 end) as DaysToRespond,
                   dateadd(day, days.seqnum - 1, r.TransactionDate) as seqdate,
                   (case when h.date is null then 1 else 0 end) as IsWorkDay
            from requests r cross join
                 (select top 20 ROW_NUMBER() over (order by (select NULL)) as seqnum
                  from information_schema.columns
                 ) days left outer join
                 holidays h
                 on dateadd(day, days.seqnum - 1, r.TransactionDate) = h.date
           ) t
     ) t
where WorkDayNum = DaysToRespond and IsWorkDay = 1

これはテストされていませんが、ここにアイデアがあります。

さて、私はこれをテストしましたが、この場合は正しい結果を返すようです:

with holidays as (
        select CAST('2012-01-01' as date) as date union all
        select CAST('2012-01-05' as date) as date union all
        select CAST('2012-01-06' as date) as date union all
        select CAST('2012-01-12' as date) as date union all
        select CAST('2012-01-13' as date) as date union all
        select CAST('2012-01-19' as date) as date union all
        select CAST('2012-01-20' as date) as date
       ),
      requests as (
        select 1 as requestId, CAST('2012-01-02' as DATE) as TransactionDate, 1 as Critical
      )

select t.*
from (select t.*,
             row_number() over (partition by t.requestid, IsWorkDay order by seqdate) as WorkDayNum
      from (select r.requestid, r.TransactionDate,
                   (case when critical = 1 then 5 else 10 end) as DaysToRespond,
                   dateadd(day, days.seqnum - 1, r.TransactionDate) as seqdate,
                   (case when h.date is null then 1 else 0 end) as IsWorkDay
            from requests r cross join
                 (select top 20 ROW_NUMBER() over (order by (select NULL)) as seqnum
                  from INFORMATION_SCHEMA.columns
                 ) days left outer join
                 holidays h
                 on dateadd(day, days.seqnum - 1, r.TransactionDate) = h.date
           ) t
     ) t
where WorkDayNum = DaysToRespond+1 and IsWorkDay = 1

このクエリは、取引日から 20 日間のシーケンスを作成します (20 日で十分ですか?)。次に、これらの日の日付を計算し、その日付を休日テーブルと比較します。

日数を数えるにはrow_number()、リクエストによるパーティショニングと、稼働日と非稼働日を使用します。選択する行は、営業日であり、取引日からの日数です。

于 2013-01-03T17:21:34.163 に答える