Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Perhitungan waktu durasi SQL

Pada beberapa kesempatan saya telah melakukan hal serupa. Pada dasarnya, pengelompokan berdasarkan pemisahan dalam urutan yang kompleks. Dasar-dasar pendekatan yang saya gunakan, sehubungan dengan masalah ini, adalah sebagai berikut:

  1. Buat tabel dengan rentang waktu yang menarik.
  2. Temukan waktu mulai untuk setiap kelompok rentang waktu yang diminati.
  3. Temukan waktu berakhir untuk setiap kelompok rentang waktu yang diminati.
  4. Gabung dengan waktu mulai dan berakhir ke daftar rentang waktu, dan grup.

Atau, secara lebih rinci:(setiap langkah ini dapat menjadi bagian dari satu CTE besar, tetapi saya telah memecahnya menjadi tabel sementara untuk kemudahan membaca...)

Langkah 1:Temukan daftar semua rentang waktu yang diminati (saya menggunakan metode yang mirip dengan yang ditautkan oleh @Brad). CATATAN:seperti yang ditunjukkan oleh @Manfred Sorg, ini mengasumsikan tidak ada "detik yang hilang" dalam data bus. Jika ada jeda pada stempel waktu, kode ini akan menafsirkan rentang tunggal sebagai dua (atau lebih) rentang berbeda.

;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

Langkah 2:Temukan waktu paling awal untuk setiap pemberhentian

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

Langkah 3:Temukan waktu terakhir untuk setiap pemberhentian

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

Langkah 4:Gabungkan semuanya bersama

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"

Terakhir, biar lengkap, beres-beres:

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. Kinerja Server Sql Dan Urutan Bidang

  2. nvarchar(maks) vs NText

  3. Batasan multiplisitas melanggar SQL Server 2008 - CodeFirst

  4. Memahami Fungsi GROUPING dan GROUPING_ID di SQL Server

  5. SQL - Konversi tipe data varchar ke tipe data datetime menghasilkan nilai di luar rentang