Genelde iki çeşit zaman aralığım var:
presence time
ve absence time
absence time
farklı tiplerde olabilir (örn. molalar, devamsızlıklar, özel gün vb.) ve zaman aralıkları çakışabilir ve / veya kesişebilir.
Öyle değil aralıklarla yalnızca uyumlu kombinasyonları, örneğin çiğ verilerde var olduğunu, kesin. örtüşen mevcudiyet aralıkları bir anlam ifade etmiyor, ama var olabilir. Sonuçta ortaya çıkan mevcudiyet zaman aralıklarını birçok yönden tanımlamaya çalıştım - benim için en rahat olan şu sıradan biri gibi görünüyor.
;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";
bazı demo verileri için bkz. SQL-Fiddle .
Ham veriler farklı tablolarda "starttime" - "endtime"
veya biçiminde bulunur "starttime" - "duration"
.
Fikir, mevcudiyet süresini tahmin etmek için her seferinde açık aralıkların "bitmasked" yuvarlanma toplamı ile her zaman damgasının sıralı bir listesini almaktı.
Keman çalışır ve farklı aralıklardaki başlangıçlar eşit olsa bile tahmini sonuçlar verir. Bu örnekte hiçbir indeks kullanılmamıştır.
Bu, sorgulanan göreve ulaşmanın doğru yolu mu yoksa bunun için daha zarif bir yol var mı?
Yanıtlama ile ilgili ise: veri miktarı, tablo başına çalışan başına on bine kadar veri kümesine kadar olacaktır. sql-2012 toplamda satır içi öncüllerin yuvarlanan toplamını hesaplamak için kullanılamaz.
Düzenle:
Sorguyu büyük miktarda test verisine (1000, 10.000, 100.000, 1 milyon) karşı yürüttüm ve çalışma zamanının katlanarak arttığını görebilirsiniz. Açıkçası bir uyarı bayrağı, değil mi?
Sorguyu değiştirdim ve ilginç bir güncellemeyle haddeleme toplamının toplanmasını kaldırdım.
Yardımcı bir tablo ekledim:
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" )
ve haddeleme toplamını hesaplayarak bu yere taşıdım:
declare @rolSum int = 0
update "timestamps" set @rolSum = "rolSum" = @rolSum + power( 2, "type" ) * "opening" from "timestamps"
SQL-Fiddle'ı buradan görebilirsiniz
"Çalışma zamanı" tablosundaki 1 milyon giriş ile ilgili çalışma süresi 3 saniyeye düştü.
Soru aynı kalır : Bunu çözmenin en etkili yolu nedir?
[this]
. Bunu çift tırnaktan daha iyi seviyorum sanırım.