2017-08-15 9 views
2

毎回最小日付をチェックして30日を追加し、それに応じてフィールドを設定する必要があります。例についてはどのように各観測および更新フラグの最小日付を動的に確認する

マイ表:

ID StartDate  EndDate 
1  2017-01-01 2017-02-01 
1  2017-01-09 2017-01-28 
1  2017-04-01 2017-04-30 
1  2017-04-05 2017-05-20 
1  2017-04-20 2017-06-12 
2  2017-06-02 2017-06-20 
2  2017-06-14 2017-07-31 
2  2017-06-14 2017-07-31 
2  2017-06-19 2017-07-31 
2  2017-06-19 2017-07-31 

はそう、ここで分(STARTDATE)が2017年1月1日です。今私はそれに30日を追加し、私のルックアップの日付は2017-01-31です。開始日がこの検索日よりも短いレコードについては、flag_1を設定する必要があります。

私のテーブルには、次のようになります。今、私は私の分の開始日の.so日(2017年1月31日)を調べ、前よりも大きく、次の最小STARTDATEを探す必要が

ID StartDate  EndDate    flag 
1  2017-01-01 2017-02-01   flag_1 
1  2017-01-09 2017-01-28   flag_1 
1  2017-04-01 2017-04-30   null 
1  2017-04-05 2017-05-20   null 
1  2017-04-20 2017-06-12   null 
2  2017-06-02 2017-06-20   null 
2  2017-06-14 2017-07-31   null 
2  2017-06-14 2017-07-31   null 
2  2017-06-19 2017-07-31   null 
2  2017-06-19 2017-07-31   null 

は2017になります-04-01。今私はそれに30日を追加し、新しいルックアップ日は 2017-05-01です。新しいルックアップ開始日2017-05-01よりも前で、前回のルックアップ日(2017-01-31)よりも古いすべてのレコードについて、フラグはflag_2になり、同じIDの最後のレコードに到達するまで同じIDで点灯しますID。私はコードの下で、レコードの最初のセットを取得するが、ループ内でこれを有し、かつ動的に更新フラグを持つと考えることができないことができ

ID StartDate  EndDate    flag 
1  2017-01-01 2017-02-01   flag_1 
1  2017-01-09 2017-01-28   flag_1 
1  2017-04-01 2017-04-30   flag_2 
1  2017-04-05 2017-05-20   flag_2 
1  2017-04-20 2017-06-12   flag_2 
2  2017-06-02 2017-06-20   flag_1 
2  2017-06-14 2017-07-31   flag_1 
2  2017-06-14 2017-07-31   flag_1 
2  2017-06-19 2017-07-31   flag_1 
2  2017-06-19 2017-07-31   flag_1 

私のファイナルテーブルは次のようになります。

select a.*,'flag_1' as flag from table a 
join 
(select cast(min(startdate) as date) as minstartdate,cast(dateadd(day,30,min(startdate)) as date) as maxstartdate,ID from table 
group by ID) adate 
on cast(adate.maxstartdate as date)> cast(a.startdate as date) 
and adate.id=a.id 
where a.id=1 
order by startdate 

誰でもこのロジックを教えてもらえますか?

答えて

0

ここに私がアプローチする方法があります。再帰的なアプローチがあるかもしれませんが、絶対に必要でない限り、再帰は使用しません。

メモ:私は、開発とテスト中にリセットしやすくするために一時テーブルで作業を行いました。インクリメントロジックを簡略化するためにフラグに整数フィールドを使用しました。

-- the setup 
Create Table SO_Check_Min_Date 
(
    ID Int 
    , StartDate Date 
    , EndDate Date 
    , Flag Int 
) 

Insert Into dbo.SO_Check_Min_Date 
(
    ID 
    , StartDate 
    , EndDate 
) 
Values 
(1,  '2017-01-01', '2017-02-01'), 
(1,  '2017-01-09', '2017-01-28'), 
(1,  '2017-04-01', '2017-04-30'), 
(1,  '2017-04-05', '2017-05-20'), 
(1,  '2017-04-20', '2017-06-12'), 
(2,  '2017-06-02', '2017-06-20'), 
(2,  '2017-06-14', '2017-07-31'), 
(2,  '2017-06-14', '2017-07-31'), 
(2,  '2017-06-19', '2017-07-31'), 
(2,  '2017-06-19', '2017-07-31') 

-- the logic 
Declare 
@Flag As Int = 0 
, @StartDate As Date 
, @LookupDate As Date 
, @ID As Int 
, @PrevID As Int = 0; 

Select 
    * 
Into 
    #Temp_SO_Check 
From SO_Check_Min_Date; 

Select * From #Temp_SO_Check As tsc -- to see that the flag field is blank 

While Exists 
(
    Select Top 1 
       1 
     From #Temp_SO_Check 
     Where Flag Is Null 
) 
Begin 
    Select Top 1 
       @ID = ID 
       , @StartDate = StartDate 
     From #Temp_SO_Check 
     Where Flag Is Null 
     Order By 
       ID 
       , StartDate; 

    If @PrevID <> @ID 
     Begin 
      Set @Flag = 1; 
      Set @PrevID = @ID; 
     End; 
    Else 
     Set @Flag = @Flag + 1; 

    Set @LookupDate = DateAdd(Day, 30, @StartDate); 

    Update 
     #Temp_SO_Check 
     Set 
     Flag = @Flag 
     Where 
     ID = @ID 
     And StartDate Between @StartDate 
        And  @LookupDate; 
End; 

Select * From #Temp_SO_Check As tsc  -- to see that it has been populated as desired 
+0

パーフェクト!これは私が探していたものです。私の要件にはいくつかのネストされたループもあります。しかし、この論理を入れ子にしてみようとしましょう。おかげでブライアンブライアン – chits

+0

あなたは大歓迎です。 WHILEループはかなり簡単に入れ子にする必要がありますが、私はそれを試みることは決してありませんでした。 – Brian

1

これは元々の質問です。ここで回答を投稿しています。あなたのループを一本化することをお勧めします。ここに2つのCTEとZEROループがあります。

declare @table table (ID int, StartDate date, EndDate date) 
Insert Into @table 
(
    ID 
    , StartDate 
    , EndDate 
) 
Values 
(1,  '2017-01-01', '2017-02-01'), 
(1,  '2017-01-09', '2017-01-28'), 
(1,  '2017-04-01', '2017-04-30'), 
(1,  '2017-04-05', '2017-05-20'), 
(1,  '2017-04-20', '2017-06-12'), 
(2,  '2017-06-02', '2017-06-20'), 
(2,  '2017-06-14', '2017-07-31'), 
(2,  '2017-06-14', '2017-07-31'), 
(2,  '2017-06-19', '2017-07-31'), 
(2,  '2017-06-19', '2017-07-31') 


;with cte as(
select 
    t1.ID 
    ,t1.StartDate 
    ,t1.EndDate 
    ,DT = (select min(StartDate) from @table t2 where t2.StartDate > DATEADD(day,30,t1.StartDate)) 
from 
    @table t1), 

cte2 as(
select 
    ID 
    ,StartDate 
    ,EndDate 
    ,dense_rank() over (order by isnull(DT,(select max(StartDate) from cte))) as Flag 
from 
    cte) 

select 
    ID 
    ,StartDate 
    ,EndDate 
    ,case when Flag % 2 = 0 then 2 else Flag % 2 end as Flag 
from cte2 
+0

@SqlZim ID用に30日間の複数のウィンドウがある場合、それがうまくいくかどうかはわかりません。私にチェックさせてください。 – scsimon

+0

これは私が一般的にこの解決策を見ている問題です。 – SqlZim

+0

私と一緒に?すべてのIDを1に変更すると、それは引き続き機能します。あなたは精緻化できますか?私はテストデータを変更しましたが、それはまだ動作しますので、私はあなたが兄弟を意味するのか分かりません。 – scsimon

関連する問題