sql >> Databáze >  >> RDS >> Sqlserver

Výpočet doby trvání SQL

Při mnoha příležitostech jsem něco podobného udělal. V podstatě seskupování založené na separacích v rámci komplexního uspořádání. Základy přístupu, který používám s ohledem na tento problém, jsou následující:

  1. Sestavte tabulku všech časových rozsahů zájmu.
  2. Najděte počáteční čas pro každou skupinu časových rozsahů zájmu.
  3. Najděte čas ukončení pro každou skupinu časových rozsahů, které vás zajímají.
  4. Připojte počáteční a koncové časy k seznamu časových rozsahů a skupin.

Nebo podrobněji:(každý z těchto kroků může být součástí jednoho velkého CTE, ale pro snazší čtení jsem to rozdělil na dočasné tabulky...)

Krok 1:Najděte seznam všech časových rozsahů zájmu (použil jsem metodu podobnou té, na kterou odkazuje @Brad). POZNÁMKA:Jak poznamenal @Manfred Sorg, předpokládá se, že v datech sběrnice nejsou žádné „chybějící sekundy“. Pokud dojde k přerušení časových razítek, bude tento kód interpretovat jeden rozsah jako dva (nebo více) odlišné rozsahy.

;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:Najděte nejbližší čas každé zastávky

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:Najděte nejnovější čas pro každou zastávku

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:Spojte vše dohromady

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"

Aby to bylo kompletní, udělejte si pořádek:

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


  1. Pro urychlení zredukujte dotazy MySQL na jeden dotaz

  2. Python 3.7, Selhalo stavební kolo pro MySql-Python

  3. Ubuntu 17:Nelze nainstalovat mysqlclient

  4. Jak vytvořit objekt JSON v MySql s booleovskou hodnotou?