Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Obliczanie czasu trwania SQL

Przy wielu okazjach robiłem coś podobnego. Zasadniczo grupowanie oparte na separacji w ramach złożonego uporządkowania. Podstawy stosowanego przeze mnie podejścia do tego problemu są następujące:

  1. Zbuduj tabelę wszystkich interesujących przedziałów czasowych.
  2. Znajdź czas rozpoczęcia dla każdej grupy interesujących przedziałów czasowych.
  3. Znajdź czas zakończenia dla każdej grupy interesujących przedziałów czasowych.
  4. Dołącz czas rozpoczęcia i zakończenia do listy przedziałów czasowych i grupy.

Lub bardziej szczegółowo:(każdy z tych kroków może być częścią jednego dużego CTE, ale podzieliłem go na tabele tymczasowe, aby ułatwić czytanie...)

Krok 1:Znajdź listę wszystkich interesujących przedziałów czasowych (użyłem metody podobnej do tej, którą łączy @Brad). UWAGA:jak zauważył @Manfred Sorg, zakłada to, że w danych autobusu nie ma „brakujących sekund”. Jeśli nastąpi przerwa w sygnaturach czasowych, ten kod zinterpretuje pojedynczy zakres jako dwa (lub więcej) różne zakresy.

;with stopSeconds as (
  select BusID, BusStopID, TimeStamp,
         [date] = cast(datediff(dd,0,TimeStamp) as datetime),
         [grp] = dateadd(ss, -row_number() over(partition by BusID order by TimeStamp), TimeStamp)
  from #test
  where BusStopID is not null
)
select BusID, BusStopID, date,
       [sTime] = dateadd(ss,datediff(ss,date,min(TimeStamp)), 0),
       [eTime] = dateadd(ss,datediff(ss,date,max(TimeStamp)), 0),
       [secondsOfStop] = datediff(ss, min(TimeStamp), max(Timestamp)),
       [sOrd] = row_number() over(partition by BusID, BusStopID order by datediff(ss,date,min(TimeStamp))),
       [eOrd] = row_number() over(partition by BusID, BusStopID order by datediff(ss,date,max(TimeStamp)))
into #ranges
from stopSeconds
group by BusID, BusStopID, date, grp

Krok 2:Znajdź najwcześniejszy czas każdego przystanku

select this.BusID, this.BusStopID, this.sTime minSTime,
       [stopOrder] = row_number() over(partition by this.BusID, this.BusStopID order by this.sTime)
into #starts
from #ranges this
  left join #ranges prev on this.BusID = prev.BusID
                        and this.BusStopID = prev.BusStopID
                        and this.sOrd = prev.sOrd+1
                        and this.sTime between dateadd(mi,-10,prev.sTime) and dateadd(mi,10,prev.sTime)
where prev.BusID is null

Krok 3:Znajdź najpóźniejszy czas każdego przystanku

select this.BusID, this.BusStopID, this.eTime maxETime,
       [stopOrder] = row_number() over(partition by this.BusID, this.BusStopID order by this.eTime)
into #ends
from #ranges this
  left join #ranges next on this.BusID = next.BusID
                        and this.BusStopID = next.BusStopID
                        and this.eOrd = next.eOrd-1
                        and this.eTime between dateadd(mi,-10,next.eTime) and dateadd(mi,10,next.eTime)
where next.BusID is null

Krok 4:Połącz wszystko razem

select r.BusID, r.BusStopID,
       [avgLengthOfStop] = avg(datediff(ss,r.sTime,r.eTime)),
       [earliestStop] = min(r.sTime),
       [latestDepart] = max(r.eTime)
from #starts s
  join #ends e on s.BusID=e.BusID
              and s.BusStopID=e.BusStopID
              and s.stopOrder=e.stopOrder
  join #ranges r on r.BusID=s.BusID
                and r.BusStopID=s.BusStopID
                and r.sTime between s.minSTime and e.maxETime
                and r.eTime between s.minSTime and e.maxETime
group by r.BusID, r.BusStopID, s.stopOrder
having count(distinct r.date) > 1 --filters out the "noise"

Na koniec, aby być kompletnym, posprzątaj:

drop table #ends
drop table #starts
drop table #ranges


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak zsumować wartość kolumn przestawnych i dodać je do innej kolumny przestawnej?

  2. Przyznawanie dostępu do jednej bazy danych użytkownikom/rolom innego

  3. serwer sql wyświetla brakujące daty

  4. zoptymalizuj zapytanie najbliższego sąsiada na 70 milionach przestrzennej chmury punktów o bardzo dużej gęstości na SQL Server 2008

  5. Jak przejść przez wszystkie tabele SQL?