Secara utama, saya punya dua jenis interval waktu:
presence time dan absence time
absence time dapat dari jenis yang berbeda (misalnya istirahat, absen, hari khusus dan sebagainya) dan interval waktu mungkin tumpang tindih dan / atau berpotongan.
Hal ini tidak pasti, bahwa hanya kombinasi yang masuk akal dari interval ada di data mentah, misalnya. interval kehadiran yang tumpang tindih tidak masuk akal, tetapi mungkin ada. Saya sudah mencoba mengidentifikasi interval waktu kehadiran yang dihasilkan dalam banyak cara sekarang - bagi saya, yang paling nyaman tampaknya adalah yang mengikuti.
;with "timestamps"
as
(
select
"id" = row_number() over ( order by "empId", "timestamp", "opening", "type" )
, "empId"
, "timestamp"
, "type"
, "opening"
from
(
select "empId", "timestamp", "type", case when "types" = 'starttime' then 1 else -1 end as "opening" from
( select "empId", "starttime", "endtime", 1 as "type" from "worktime" ) as data
unpivot ( "timestamp" for "types" in ( "starttime", "endtime" ) ) as pvt
union all
select "empId", "timestamp", "type", case when "types" = 'starttime' then 1 else -1 end as "opening" from
( select "empId", "starttime", "endtime", 2 as "type" from "break" ) as data
unpivot ( "timestamp" for "types" in ( "starttime", "endtime" ) ) as pvt
union all
select "empId", "timestamp", "type", case when "types" = 'starttime' then 1 else -1 end as "opening" from
( select "empId", "starttime", "endtime", 3 as "type" from "absence" ) as data
unpivot ( "timestamp" for "types" in ( "starttime", "endtime" ) ) as pvt
) as data
)
select
T1."empId"
, "starttime" = T1."timestamp"
, "endtime" = T2."timestamp"
from
"timestamps" as T1
left join "timestamps" as T2
on T2."empId" = T1."empId"
and T2."id" = T1."id" + 1
left join "timestamps" as RS
on RS."empId" = T2."empId"
and RS."id" <= T1."id"
group by
T1."empId", T1."timestamp", T2."timestamp"
having
(sum( power( 2, RS."type" ) * RS."opening" ) = 2)
order by
T1."empId", T1."timestamp";
lihat SQL-Fiddle untuk beberapa data demo.
Data mentah ada di berbagai tabel dalam bentuk "starttime" - "endtime"atau "starttime" - "duration".
Idenya adalah untuk mendapatkan daftar yang terurut dari setiap cap waktu dengan jumlah bergulir "bitmasked" dari interval terbuka pada setiap waktu untuk memperkirakan waktu kehadiran.
Biola bekerja dan memberikan hasil yang diperkirakan, meskipun waktu jeda dari interval yang berbeda sama. Tidak ada indeks yang digunakan dalam contoh ini.
Apakah ini cara yang tepat untuk mencapai tugas yang dipertanyakan atau apakah ada cara yang lebih elegan untuk ini?
Jika relevan untuk menjawab: jumlah data akan mencapai beberapa sepuluh ribu dataset per karyawan per tabel. sql-2012 tidak tersedia untuk menghitung jumlah bergulir para pendahulu inline secara agregat.
edit:
Hanya menjalankan kueri terhadap jumlah testdata yang lebih besar (1000, 10.000, 100.000, 1 juta) dan dapat melihat bahwa runtime meningkat secara eksponensial. Jelas sebuah bendera peringatan, bukan?
Saya mengubah kueri dan menghapus agregasi jumlah bergulir dengan pembaruan yang unik.
Saya telah menambahkan tabel tambahan:
create table timestamps
(
"id" int
, "empId" int
, "timestamp" datetime
, "type" int
, "opening" int
, "rolSum" int
)
create nonclustered index "idx" on "timestamps" ( "rolSum" ) include ( "id", "empId", "timestamp" )
dan saya pindah menghitung rolling sum ke tempat ini:
declare @rolSum int = 0
update "timestamps" set @rolSum = "rolSum" = @rolSum + power( 2, "type" ) * "opening" from "timestamps"
Runtime menurun menjadi 3 detik mengenai 1 juta entri dalam tabel "worktime".
Pertanyaan tetap sama : Apa cara paling efektif untuk menyelesaikan ini?
[this]. Saya hanya suka itu lebih baik daripada tanda kutip ganda, saya kira.