sql >> Databasteknik >  >> RDS >> Sqlserver

Beräkning av SQL varaktighetstid

Vid ett antal tillfällen har jag gjort något liknande. I huvudsak, gruppering baserad på separationer inom en komplex ordning. Grunderna i det tillvägagångssätt jag använder, med avseende på detta problem, är följande:

  1. Skapa en tabell över alla tidsintervall av intresse.
  2. Hitta starttiden för varje grupp av tidsintervall av intresse.
  3. Hitta sluttiden för varje grupp av tidsintervall av intresse.
  4. Anslut start- och sluttiderna till listan över tidsintervall och grupp.

Eller mer detaljerat:(vart och ett av dessa steg kan vara en del av en stor CTE, men jag har delat upp det i tillfälliga tabeller för att underlätta läsningen...)

Steg 1:Hitta listan över alla tidsintervall av intresse (jag använde en metod som liknar den som länkas till av @Brad). OBS:som @Manfred Sorg påpekade, förutsätter detta att det inte finns några "saknade sekunder" i en busss data. Om det finns ett avbrott i tidsstämplarna kommer den här koden att tolka det enskilda intervallet som två (eller flera) distinkta intervall.

;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

Steg 2:Hitta den tidigaste tiden för varje stopp

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

Steg 3:Hitta den senaste tiden för varje stopp

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

Steg 4:Slå ihop allt

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"

Slutligen, för att vara komplett, städa upp:

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


  1. Oracle SEQUENCE.Currval problem i CodeIgniter

  2. fatalt fel 'stdio.h' Python 2.7.3 på Mac OS X 10.7.5

  3. mysql group_concat med en räkning inuti?

  4. Hur man konverterar en postgres-databas till sqlite