Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

SQL изчисляване на продължителността на времето

В редица случаи съм правил нещо подобно. По същество групиране въз основа на разделяне в рамките на комплексно подреждане. Основите на подхода, който използвам по отношение на този проблем, са следните:

  1. Създайте таблица с всички интересни времеви диапазони.
  2. Намерете началния час за всяка група от периоди от време, които представляват интерес.
  3. Намерете крайния час за всяка група от интересни времеви диапазони.
  4. Присъединете началния и крайния час към списъка с периоди от време и групирайте.

Или, по-подробно:(всяка от тези стъпки може да бъде част от един голям CTE, но аз съм го разделил на временни таблици за по-лесно четене...)

Стъпка 1:Намерете списъка с всички интересни времеви диапазони (използвах метод, подобен на този, към който е свързана от @Brad). ЗАБЕЛЕЖКА:както посочи @Manfred Sorg, това предполага, че няма „липсващи секунди“ в данните на автобуса. Ако има прекъсване във времевите клейма, този код ще интерпретира единичния диапазон като два (или повече) различни диапазона.

;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

Стъпка 2:Намерете най-ранния час за всяко спиране

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

Стъпка 3:Намерете най-новия час за всяко спиране

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

Стъпка 4:Свържете всичко заедно

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"

И накрая, за да бъде пълно, подредете:

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. Как да извлечете последната автоматично увеличена стойност в MS-Access като @@Identity в Sql Server

  2. Какво е съхранената процедура и защо съхранената процедура?

  3. Извличане на URL адреси от уебсайт?

  4. Вмъкване на множество стойности в SQL база данни от EXCEL чрез VBA скрипт

  5. Как да получите стойност на квадратчето за отметка от gridview, когато квадратчето за отметка OnCheckedChanged