Trong chính, tôi đã có hai loại khoảng thời gian:
presence time
và absence time
absence time
có thể có nhiều loại khác nhau (ví dụ: nghỉ, vắng mặt, ngày đặc biệt, v.v.) và khoảng thời gian có thể chồng chéo và / hoặc giao nhau.
Đó là không chắc chắn, rằng chỉ có sự kết hợp hợp lý của chu kỳ tồn tại trong dữ liệu thô, ví dụ. sự hiện diện chồng chéo không có ý nghĩa, nhưng có thể tồn tại. Bây giờ tôi đã cố gắng xác định các khoảng thời gian hiện diện theo nhiều cách - đối với tôi, sự thoải mái nhất dường như là theo dõi.
;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";
xem SQL-Fiddle để biết một số dữ liệu demo.
Dữ liệu thô tồn tại trong các bảng khác nhau ở dạng "starttime" - "endtime"
hoặc "starttime" - "duration"
.
Ý tưởng là để có được một danh sách theo thứ tự của mỗi dấu thời gian với tổng số lần mở "bitmasked" mỗi lần để ước tính thời gian hiện diện.
Fiddle hoạt động và cho kết quả ước tính, ngay cả khi thời gian bắt đầu của các khoảng khác nhau là bằng nhau. Không có chỉ số được sử dụng trong ví dụ này.
Đây có phải là cách đúng đắn để đạt được nhiệm vụ nghi vấn hay có cách nào thanh lịch hơn cho việc này?
Nếu có liên quan để trả lời: lượng dữ liệu sẽ lên tới vài nghìn bộ dữ liệu cho mỗi nhân viên mỗi bảng. sql-2012 không có sẵn để tính tổng của các tiền thân nội tuyến trong tổng hợp.
biên tập:
Chỉ cần thực hiện truy vấn đối với số lượng testdata lớn hơn (1000, 10.000, 100.000, 1 triệu) và có thể thấy thời gian chạy tăng theo cấp số nhân. Rõ ràng là một lá cờ cảnh báo, phải không?
Tôi đã thay đổi truy vấn và loại bỏ tổng hợp cán tổng bằng một bản cập nhật kỳ quặc.
Tôi đã thêm một bảng phụ trợ:
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" )
và tôi đã di chuyển tính toán tổng số đến nơi này:
declare @rolSum int = 0
update "timestamps" set @rolSum = "rolSum" = @rolSum + power( 2, "type" ) * "opening" from "timestamps"
Thời gian chạy giảm xuống còn 3 giây liên quan đến 1 triệu mục trong "thời gian làm việc".
Câu hỏi vẫn giữ nguyên : Cách hiệu quả nhất để giải quyết vấn đề này là gì?
[this]
. Tôi chỉ thích điều đó tốt hơn so với trích dẫn kép, tôi đoán.