2013-05-16 8 views
5

私は時間の連続したスパンに対して開始日と終了日の組み合わせを取得しようとしています。スパンは複数の行にまたがることができます。最初の行の終了日は次の行の終了日と同じです。意図した結果は、連続した日付範囲と、その範囲で働いた時間の合計を示すことです。SQL:複数の行にわたる連続した日付範囲を見つけるか?

person startdate    enddate     hours 
------ ----------------------- ----------------------- ------ 
5163 2013-04-29 07:00:00.000 2013-04-29 11:00:00.000 4.00 
5163 2013-04-29 11:30:00.000 2013-04-29 15:30:00.000 4.00 
5163 2013-04-29 15:30:00.000 2013-04-29 19:06:00.000 3.60 
5851 2013-05-02 19:00:00.000 2013-05-02 23:00:00.000 4.00 
5851 2013-05-02 23:00:00.000 2013-05-03 00:00:00.000 1.00 
5851 2013-05-03 00:00:00.000 2013-05-03 00:31:00.000 0.52 

上記のデータから、私は次のことが必要です。各人と新しい(非連続)日付スパン

person startdate    enddate     hours 
------ ----------------------- ----------------------- ------ 
5163 2013-04-29 07:00:00.000 2013-04-29 11:00:00.000 4.00 
5163 2013-04-29 11:30:00.000 2013-04-29 19:06:00.000 7.60 
5851 2013-05-02 19:00:00.000 2013-05-03 00:31:00.000 5.52 

、次の行のSTARTDATEに現在の行の終了日を比較します。同じ場合は、時間を累計して、enddate/startdateが等しくないまで行の処理を続行します。

環境はSQL Server 2008 R2です。 row_numberとpartition()関数を使用して自己結合を含むクエリを試しましたが、成功した解決策を得ることはできませんでした。ありがとう!

編集:RichardTheKiwiのソリューションのデータフローは次のとおりです。私は1人で1週間実行して、1週間分のパンチで再帰が生成されるのを確認しました。

declare @startdate datetime; 
    set @startdate = '20130429'; 
declare @enddate datetime; 
    set @enddate = '20130506'; 

with tbl as (
select 
PERSONNUM, 
STARTDTM, 
ENDDTM, 
convert(decimal(10,2),1.0 * TIMEINSECONDS/3600) as timeinhours 
from vp_totals 
where paycodetype = 'p' 
and applydate >= @startdate and APPLYDATE < @enddate 
and (paycodename like '%regular%' 
    or paycodename like '%overtime%' 
    or PAYCODENAME like '%double time%') 
and (PAYCODENAME not like '%shift premium%') 
and PERSONNUM = 'loh-5851' 
) 

select * from tbl order by startdtm -- 27 rows 


PERSONNUM  STARTDTM   ENDDTM    timeinhours 
LOH-5851  2013-04-29 14:30:00 2013-04-29 18:30:00 4.0000 
LOH-5851  2013-04-29 19:00:00 2013-04-29 23:00:00 4.0000 
LOH-5851  2013-04-29 23:00:00 2013-04-30 00:00:00 1.0000 
LOH-5851  2013-04-30 00:00:00 2013-04-30 00:11:00 0.1800 
LOH-5851  2013-04-30 14:45:00 2013-04-30 18:45:00 4.0000 
LOH-5851  2013-04-30 19:15:00 2013-04-30 23:00:00 3.7500 
LOH-5851  2013-04-30 23:00:00 2013-04-30 23:15:00 0.2500 
LOH-5851  2013-04-30 23:15:00 2013-05-01 00:00:00 0.7500 
LOH-5851  2013-05-01 00:00:00 2013-05-01 00:11:00 0.1800 
LOH-5851  2013-05-01 14:30:00 2013-05-01 18:30:00 4.0000 
LOH-5851  2013-05-01 19:00:00 2013-05-01 23:00:00 4.0000 
LOH-5851  2013-05-01 23:00:00 2013-05-02 00:00:00 1.0000 
LOH-5851  2013-05-02 00:00:00 2013-05-02 00:22:00 0.3700 
LOH-5851  2013-05-02 14:30:00 2013-05-02 18:30:00 4.0000 
LOH-5851  2013-05-02 19:00:00 2013-05-02 23:00:00 4.0000 
LOH-5851  2013-05-02 23:00:00 2013-05-03 00:00:00 1.0000 
LOH-5851  2013-05-03 00:00:00 2013-05-03 00:31:00 0.5200 
LOH-5851  2013-05-03 14:45:00 2013-05-03 17:45:00 3.0000 
LOH-5851  2013-05-03 17:45:00 2013-05-03 18:45:00 1.0000 
LOH-5851  2013-05-03 19:15:00 2013-05-03 23:00:00 3.7500 
LOH-5851  2013-05-03 23:00:00 2013-05-03 23:15:00 0.2500 
LOH-5851  2013-05-03 23:15:00 2013-05-04 00:00:00 0.7500 
LOH-5851  2013-05-04 00:00:00 2013-05-04 00:15:00 0.2500 
LOH-5851  2013-05-04 14:00:00 2013-05-04 18:00:00 4.0000 
LOH-5851  2013-05-04 18:30:00 2013-05-04 22:30:00 4.0000 
LOH-5851  2013-05-04 22:30:00 2013-05-04 23:00:00 0.5000 
LOH-5851  2013-05-04 23:00:00 2013-05-04 23:30:00 0.5000 


,cte as (
    select personnum, startdtm, enddtm, timeinhours 
    from tbl 
    union all 
    select t.personnum, cte.startdtm, t.enddtm, cast(cte.timeinhours + t.timeinhours as decimal(10,2)) 
    from cte 
    join tbl t on cte.personnum = t.personnum and cte.enddtm = t.startdtm 
) 

select * from cte order by startdtm, timeinhours option (maxrecursion 32000) -- 52 rows 



personnum  startdtm   enddtm    timeinhours 
LOH-5851  2013-04-29 14:30:00 2013-04-29 18:30:00 4.0000 
LOH-5851  2013-04-29 19:00:00 2013-04-29 23:00:00 4.0000 
LOH-5851  2013-04-29 19:00:00 2013-04-30 00:00:00 5.0000 
LOH-5851  2013-04-29 19:00:00 2013-04-30 00:11:00 5.1800 
LOH-5851  2013-04-29 23:00:00 2013-04-30 00:00:00 1.0000 
LOH-5851  2013-04-29 23:00:00 2013-04-30 00:11:00 1.1800 
LOH-5851  2013-04-30 00:00:00 2013-04-30 00:11:00 0.1800 
LOH-5851  2013-04-30 14:45:00 2013-04-30 18:45:00 4.0000 
LOH-5851  2013-04-30 19:15:00 2013-04-30 23:00:00 3.7500 
LOH-5851  2013-04-30 19:15:00 2013-04-30 23:15:00 4.0000 
LOH-5851  2013-04-30 19:15:00 2013-05-01 00:00:00 4.7500 
LOH-5851  2013-04-30 19:15:00 2013-05-01 00:11:00 4.9300 
LOH-5851  2013-04-30 23:00:00 2013-04-30 23:15:00 0.2500 
LOH-5851  2013-04-30 23:00:00 2013-05-01 00:00:00 1.0000 
LOH-5851  2013-04-30 23:00:00 2013-05-01 00:11:00 1.1800 
LOH-5851  2013-04-30 23:15:00 2013-05-01 00:00:00 0.7500 
LOH-5851  2013-04-30 23:15:00 2013-05-01 00:11:00 0.9300 
LOH-5851  2013-05-01 00:00:00 2013-05-01 00:11:00 0.1800 
LOH-5851  2013-05-01 14:30:00 2013-05-01 18:30:00 4.0000 
LOH-5851  2013-05-01 19:00:00 2013-05-01 23:00:00 4.0000 
LOH-5851  2013-05-01 19:00:00 2013-05-02 00:00:00 5.0000 
LOH-5851  2013-05-01 19:00:00 2013-05-02 00:22:00 5.3700 
LOH-5851  2013-05-01 23:00:00 2013-05-02 00:00:00 1.0000 
LOH-5851  2013-05-01 23:00:00 2013-05-02 00:22:00 1.3700 
LOH-5851  2013-05-02 00:00:00 2013-05-02 00:22:00 0.3700 
LOH-5851  2013-05-02 14:30:00 2013-05-02 18:30:00 4.0000 
LOH-5851  2013-05-02 19:00:00 2013-05-02 23:00:00 4.0000 
LOH-5851  2013-05-02 19:00:00 2013-05-03 00:00:00 5.0000 
LOH-5851  2013-05-02 19:00:00 2013-05-03 00:31:00 5.5200 
LOH-5851  2013-05-02 23:00:00 2013-05-03 00:00:00 1.0000 
LOH-5851  2013-05-02 23:00:00 2013-05-03 00:31:00 1.5200 
LOH-5851  2013-05-03 00:00:00 2013-05-03 00:31:00 0.5200 
LOH-5851  2013-05-03 14:45:00 2013-05-03 17:45:00 3.0000 
LOH-5851  2013-05-03 14:45:00 2013-05-03 18:45:00 4.0000 
LOH-5851  2013-05-03 17:45:00 2013-05-03 18:45:00 1.0000 
LOH-5851  2013-05-03 19:15:00 2013-05-03 23:00:00 3.7500 
LOH-5851  2013-05-03 19:15:00 2013-05-03 23:15:00 4.0000 
LOH-5851  2013-05-03 19:15:00 2013-05-04 00:00:00 4.7500 
LOH-5851  2013-05-03 19:15:00 2013-05-04 00:15:00 5.0000 
LOH-5851  2013-05-03 23:00:00 2013-05-03 23:15:00 0.2500 
LOH-5851  2013-05-03 23:00:00 2013-05-04 00:00:00 1.0000 
LOH-5851  2013-05-03 23:00:00 2013-05-04 00:15:00 1.2500 
LOH-5851  2013-05-03 23:15:00 2013-05-04 00:00:00 0.7500 
LOH-5851  2013-05-03 23:15:00 2013-05-04 00:15:00 1.0000 
LOH-5851  2013-05-04 00:00:00 2013-05-04 00:15:00 0.2500 
LOH-5851  2013-05-04 14:00:00 2013-05-04 18:00:00 4.0000 
LOH-5851  2013-05-04 18:30:00 2013-05-04 22:30:00 4.0000 
LOH-5851  2013-05-04 18:30:00 2013-05-04 23:00:00 4.5000 
LOH-5851  2013-05-04 18:30:00 2013-05-04 23:30:00 5.0000 
LOH-5851  2013-05-04 22:30:00 2013-05-04 23:00:00 0.5000 
LOH-5851  2013-05-04 22:30:00 2013-05-04 23:30:00 1.0000 
LOH-5851  2013-05-04 23:00:00 2013-05-04 23:30:00 0.5000 



,cte2 as (
    select *, rn = row_number() over (partition by personnum, enddtm order by startdtm) 
    from cte 
) 

select * from cte2 order by startdtm, rn -- 52 rows 


personnum  startdtm   enddtm    timeinhours  rn 
LOH-5851  2013-04-29 14:30:00 2013-04-29 18:30:00 4.0000    1 
LOH-5851  2013-04-29 19:00:00 2013-04-29 23:00:00 4.0000    1 
LOH-5851  2013-04-29 19:00:00 2013-04-30 00:00:00 5.0000    1 
LOH-5851  2013-04-29 19:00:00 2013-04-30 00:11:00 5.1800    1 
LOH-5851  2013-04-29 23:00:00 2013-04-30 00:11:00 1.1800    2 
LOH-5851  2013-04-29 23:00:00 2013-04-30 00:00:00 1.0000    2 
LOH-5851  2013-04-30 00:00:00 2013-04-30 00:11:00 0.1800    3 
LOH-5851  2013-04-30 14:45:00 2013-04-30 18:45:00 4.0000    1 
LOH-5851  2013-04-30 19:15:00 2013-04-30 23:00:00 3.7500    1 
LOH-5851  2013-04-30 19:15:00 2013-04-30 23:15:00 4.0000    1 
LOH-5851  2013-04-30 19:15:00 2013-05-01 00:11:00 4.9300    1 
LOH-5851  2013-04-30 19:15:00 2013-05-01 00:00:00 4.7500    1 
LOH-5851  2013-04-30 23:00:00 2013-05-01 00:00:00 1.0000    2 
LOH-5851  2013-04-30 23:00:00 2013-05-01 00:11:00 1.1800    2 
LOH-5851  2013-04-30 23:00:00 2013-04-30 23:15:00 0.2500    2 
LOH-5851  2013-04-30 23:15:00 2013-05-01 00:11:00 0.9300    3 
LOH-5851  2013-04-30 23:15:00 2013-05-01 00:00:00 0.7500    3 
LOH-5851  2013-05-01 00:00:00 2013-05-01 00:11:00 0.1800    4 
LOH-5851  2013-05-01 14:30:00 2013-05-01 18:30:00 4.0000    1 
LOH-5851  2013-05-01 19:00:00 2013-05-01 23:00:00 4.0000    1 
LOH-5851  2013-05-01 19:00:00 2013-05-02 00:00:00 5.0000    1 
LOH-5851  2013-05-01 19:00:00 2013-05-02 00:22:00 5.3700    1 
LOH-5851  2013-05-01 23:00:00 2013-05-02 00:22:00 1.3700    2 
LOH-5851  2013-05-01 23:00:00 2013-05-02 00:00:00 1.0000    2 
LOH-5851  2013-05-02 00:00:00 2013-05-02 00:22:00 0.3700    3 
LOH-5851  2013-05-02 14:30:00 2013-05-02 18:30:00 4.0000    1 
LOH-5851  2013-05-02 19:00:00 2013-05-02 23:00:00 4.0000    1 
LOH-5851  2013-05-02 19:00:00 2013-05-03 00:00:00 5.0000    1 
LOH-5851  2013-05-02 19:00:00 2013-05-03 00:31:00 5.5200    1 
LOH-5851  2013-05-02 23:00:00 2013-05-03 00:31:00 1.5200    2 
LOH-5851  2013-05-02 23:00:00 2013-05-03 00:00:00 1.0000    2 
LOH-5851  2013-05-03 00:00:00 2013-05-03 00:31:00 0.5200    3 
LOH-5851  2013-05-03 14:45:00 2013-05-03 17:45:00 3.0000    1 
LOH-5851  2013-05-03 14:45:00 2013-05-03 18:45:00 4.0000    1 
LOH-5851  2013-05-03 17:45:00 2013-05-03 18:45:00 1.0000    2 
LOH-5851  2013-05-03 19:15:00 2013-05-03 23:00:00 3.7500    1 
LOH-5851  2013-05-03 19:15:00 2013-05-03 23:15:00 4.0000    1 
LOH-5851  2013-05-03 19:15:00 2013-05-04 00:00:00 4.7500    1 
LOH-5851  2013-05-03 19:15:00 2013-05-04 00:15:00 5.0000    1 
LOH-5851  2013-05-03 23:00:00 2013-05-04 00:15:00 1.2500    2 
LOH-5851  2013-05-03 23:00:00 2013-05-04 00:00:00 1.0000    2 
LOH-5851  2013-05-03 23:00:00 2013-05-03 23:15:00 0.2500    2 
LOH-5851  2013-05-03 23:15:00 2013-05-04 00:00:00 0.7500    3 
LOH-5851  2013-05-03 23:15:00 2013-05-04 00:15:00 1.0000    3 
LOH-5851  2013-05-04 00:00:00 2013-05-04 00:15:00 0.2500    4 
LOH-5851  2013-05-04 14:00:00 2013-05-04 18:00:00 4.0000    1 
LOH-5851  2013-05-04 18:30:00 2013-05-04 22:30:00 4.0000    1 
LOH-5851  2013-05-04 18:30:00 2013-05-04 23:00:00 4.5000    1 
LOH-5851  2013-05-04 18:30:00 2013-05-04 23:30:00 5.0000    1 
LOH-5851  2013-05-04 22:30:00 2013-05-04 23:30:00 1.0000    2 
LOH-5851  2013-05-04 22:30:00 2013-05-04 23:00:00 0.5000    2 
LOH-5851  2013-05-04 23:00:00 2013-05-04 23:30:00 0.5000    3 


select personnum, startdtm, max(enddtm) enddtm, max(timeinhours) timeinhours 
from cte2 
where rn=1 
group by personnum, startdtm 
order by personnum, startdtm 
option (maxrecursion 32000) -- 12 rows 


personnum  startdtm   enddtm    timeinhours 
LOH-5851  2013-04-29 14:30:00 2013-04-29 18:30:00 4.0000 
LOH-5851  2013-04-29 19:00:00 2013-04-30 00:11:00 5.1800 
LOH-5851  2013-04-30 14:45:00 2013-04-30 18:45:00 4.0000 
LOH-5851  2013-04-30 19:15:00 2013-05-01 00:11:00 4.9300 
LOH-5851  2013-05-01 14:30:00 2013-05-01 18:30:00 4.0000 
LOH-5851  2013-05-01 19:00:00 2013-05-02 00:22:00 5.3700 
LOH-5851  2013-05-02 14:30:00 2013-05-02 18:30:00 4.0000 
LOH-5851  2013-05-02 19:00:00 2013-05-03 00:31:00 5.5200 
LOH-5851  2013-05-03 14:45:00 2013-05-03 18:45:00 4.0000 
LOH-5851  2013-05-03 19:15:00 2013-05-04 00:15:00 5.0000 
LOH-5851  2013-05-04 14:00:00 2013-05-04 18:00:00 4.0000 
LOH-5851  2013-05-04 18:30:00 2013-05-04 23:30:00 5.0000 

クエリは、少量のデータのために完璧に動作しますが、給与期間(通常1週間)のために予想される従業員の人口のために実行したときに、醜い最大再帰エラーメッセージが表示されます。

編集編集:再帰問題のRichardの修正に関するコメントを参照してください。

答えて

4

サンプル・データ

create table tbl (person int, startdate datetime, enddate datetime, hours decimal(10,2)); 
insert tbl values 
(5163 ,'2013-04-29 07:00:00.000' ,'2013-04-29 11:00:00.000', 4.00), 
(5163 ,'2013-04-29 11:30:00.000' ,'2013-04-29 15:30:00.000', 4.00), 
(5163 ,'2013-04-29 15:30:00.000' ,'2013-04-29 19:06:00.000', 3.60), 
(5851 ,'2013-05-02 19:00:00.000' ,'2013-05-02 23:00:00.000', 4.00), 
(5851 ,'2013-05-02 23:00:00.000' ,'2013-05-03 00:00:00.000', 1.00), 
(5851 ,'2013-05-03 00:00:00.000' ,'2013-05-03 00:31:00.000', 0.52); 

クエリ

;with cte as (
    select person, startdate, enddate, hours 
    from tbl 
    union all 
    select t.person, cte.startdate, t.enddate, cast(cte.hours + t.hours as decimal(10,2)) 
    from cte 
    join tbl t on cte.person = t.person and cte.enddate = t.startdate 
), cte2 as (
    select *, rn = row_number() over (partition by person, enddate order by startdate) 
    from cte 
) 
select person, startdate, max(enddate) enddate, max(hours) hours 
from cte2 
where rn=1 
group by person, startdate 
order by person, startdate; 

結果

person  startdate    enddate     hours 
----------- ----------------------- ----------------------- ------- 
5163  2013-04-29 07:00:00.000 2013-04-29 11:00:00.000 4.00 
5163  2013-04-29 11:30:00.000 2013-04-29 19:06:00.000 7.60 
5851  2013-05-02 19:00:00.000 2013-05-03 00:31:00.000 5.52 
+0

こんにちはリチャードは、このソリューションをありがとう!私はこれを答えたものとしてマークしたいと思います....提供されたサンプルデータで動作しますが、実動データを実行すると、 "ステートメントが終了しました"というエラーメッセージが表示されます。ヒント "option(maxrecursion 32000)"を使用した後でさえエラーを受け取りました。生産データは約600行で、クエリには最大1,500行が必要です。再帰問題を回避する別の方法がありますか? – user2391335

+0

終了日=開始日のレコードがあると思います。これは無限の再帰を引き起こすと考えられる(現時点で)私が考えることができる唯一のものです。あなたは 'cte.person = t.personとcte.enddate = t.startdateとt.enddate!= t.startdate'から' cte join tbl tを使用してこれを防ぐことができます。 – RichardTheKiwi

+0

もう一度、Richard!提案された変更は、再帰問題を修正するように見え、サンプルユーザーの出力が正しいように見えます。 – user2391335

関連する問題