主に、2種類の時間間隔があります。
presence time
そして absence time
absence time
さまざまなタイプ(休憩、欠席、特別な日など)にすることができ、時間間隔が重複したり交差したりする場合があります。
生データに存在する区間のもっともらしい組み合わせだけが存在するかどうかは確かではありません。存在間隔の重複は意味がありませんが、存在する場合があります。結果として得られるプレゼンスタイムインターバルをさまざまな方法で特定しようとしましたが、私にとって、最も快適なのは次のインターバルのようです。
;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";
いくつかのデモデータについては、SQL-Fiddleを参照してください。
生データは、"starttime" - "endtime"
またはの形式でさまざまなテーブルに存在し"starttime" - "duration"
ます。
アイデアは、プレゼンス時間を推定するために、各時間で開いた間隔の「ビットマスクされた」ローリング合計ですべてのタイムスタンプの順序付きリストを取得することでした。
フィドルは機能し、異なる間隔のスタータイムが等しい場合でも、推定結果を提供します。この例では、インデックスは使用されていません。
これは疑わしいタスクを達成するための正しい方法ですか、これよりエレガントな方法はありますか?
回答に関連する場合:データ量は、テーブルごとに従業員あたり最大数万のデータセットになります。sql-2012は、先行バージョンのローリング合計をインラインで集計して計算するために使用できません。
編集:
大量のテストデータ(1000、10000、100.000、100万)に対してクエリを実行すると、実行時間が指数関数的に増加することがわかります。明らかに警告フラグですよね?
クエリを変更し、風変わりな更新によってローリングサムの集計を削除しました。
補助テーブルを追加しました:
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" )
そして、ローリング合計の計算をこの場所に移動しました:
declare @rolSum int = 0
update "timestamps" set @rolSum = "rolSum" = @rolSum + power( 2, "type" ) * "opening" from "timestamps"
「worktime」テーブルの100万エントリに関して、実行時間は3秒に減少しました。
質問は変わりません:これを解決する最も効果的な方法は何ですか?
[this]
。私はそれを二重引用符よりも好きだと思います。