sql >> Database >  >> RDS >> Sqlserver

Berekening van SQL-duurtijd

Ik heb een aantal keer iets soortgelijks gedaan. In wezen groeperen op basis van scheidingen binnen een complexe ordening. De basis van de benadering die ik gebruik, met betrekking tot dit probleem, is als volgt:

  1. Maak een tabel met alle interessante tijdsbereiken.
  2. Vind de starttijd voor elke groep van interessegebieden.
  3. Vind de eindtijd voor elke groep van interessegebieden.
  4. Voeg de begin- en eindtijden toe aan de lijst met tijdbereiken en groep.

Of, meer in detail:(elk van deze stappen kan deel uitmaken van één grote CTE, maar ik heb het opgesplitst in tijdelijke tabellen om het lezen te vergemakkelijken...)

Stap 1:Zoek de lijst met alle interessegebieden (ik heb een methode gebruikt die vergelijkbaar is met die van @Brad). OPMERKING:zoals @Manfred Sorg al aangaf, veronderstelt dit dat er geen "ontbrekende seconden" zijn in de data van een bus. Als er een onderbreking is in de tijdstempels, interpreteert deze code het enkele bereik als twee (of meer) verschillende bereiken.

;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

Stap 2:Zoek de vroegste tijd voor elke stop

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

Stap 3:Vind de laatste tijd voor elke stop

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

Stap 4:Voeg alles samen

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"

Eindelijk, om compleet te zijn, opruimen:

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


  1. Recursieve CTE-stopvoorwaarde voor lussen

  2. mysql SELECTEER de beste van elke categorie in een enkele tabel

  3. Standaardwaarde voor lege integervelden bij het importeren van CSV-gegevens in MySQL

  4. Hoe een tijdstempel in Java te verkrijgen en op te slaan in de MySQL-database?