Próbuję uzyskać kombinację daty rozpoczęcia i zakończenia dla nieprzerwanych zakresów czasu. Rozpiętości mogą przekraczać wiele wierszy, gdzie data zakończenia pierwszego wiersza jest taka sama jak data zakończenia następnego wiersza. Celem jest pokazanie ciągłego zakresu dat z sumą godzin przepracowanych dla tego zakresu.SQL: znaleźć ciągłe zakresy dat w wielu wierszach?
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
Z powyższych danych chcę następujące.
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
Dla każdej osoby i nowego (nieciągłej) zakresu dat, porównaj ENDDATE wybranym wierszu, aby STARTDATE następnego rzędu jest. Jeśli są takie same, akumuluj godziny i kontynuuj przetwarzanie wierszy, dopóki data końcowa/data początkowa nie będą takie same.
Środowisko to SQL Server 2008 R2. Próbowałem kwerendy z udziałem self join, używając funkcji row_number i partition(), ale nie udało się uzyskać udanego rozwiązania. Dzięki!
edytuj: Oto przepływ danych dla rozwiązania RichardTheKiwi - uruchomiłem go dla jednej osoby, aby sprawdzić, ile rekursji generuje tygodniowy cios.
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
Kwerenda działa idealnie dla małych ilości danych, ale kiedy uruchomić dla oczekiwanego populacji pracowników na okres wypłaty (zwykle jeden tydzień), pojawia się brzydki maks rekursji komunikat o błędzie.
edytuj edytuj: zobacz komentarze do poprawki Richarda dla problemu rekursji.
Cześć Richard, dziękuję za to rozwiązanie! Chcę oznaczyć to jako udzielone .... Chociaż działa z przykładowymi danymi dostarczonymi, po uruchomieniu nad danymi produkcyjnymi, otrzymuję komunikat "Zakończono instrukcję Maksymalna rekurencja 100 została wyczerpana przed zakończeniem instrukcji.". Otrzymał nawet błąd po użyciu podpowiedzi "opcja (maxrecursion 32000)". Dane produkcyjne to około 600 wierszy i oczekuję do 1500 wierszy dla zapytania. Czy istnieje alternatywna metoda, która działa wokół problemu rekursji? – user2391335
Myślę, że masz jakiś rekord, w którym data końcowa = data rozpoczęcia. Jest to jedyna rzecz, o której mogę myśleć (w tej chwili), która spowodowałaby nieskończoną rekursję. Możesz temu zapobiec używając 'z cte join tbl t na cte.person = t.person i cte.enddate = t.startdate i t.enddate! = T.startdate' – RichardTheKiwi
Jeszcze raz dziękuję, Richard! Proponowana zmiana wygląda na naprawienie problemu rekursji, a wynik dla mojej przykładowej osoby wygląda poprawnie. – user2391335