7

継続的な作業時間の開始日と終了日の組み合わせを取得しようとしています。スパンは複数の行にまたがることができ、最初の行の終了日は次の行の終了日と同じです。意図した結果は、連続した日付範囲を、その範囲で働いた時間の合計とともに表示することです。

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

各人物と新しい (連続していない) 期間について、現在の行の終了日と次の行の開始日を比較します。それらが同じである場合、時間を累積し、終了日/開始日が等しくなくなるまで行の処理を続けます。

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

編集: RichardTheKiwi のソリューションのデータ フローは次のとおりです。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 週間) に予想される従業員数に対して実行すると、醜い max recursions エラー メッセージが表示されます。

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

4

1 に答える 1

6

サンプルデータ

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
于 2013-05-16T19:47:36.107 に答える