Em geral, tenho dois tipos de intervalos de tempo:
presence time
e absence time
absence time
podem ser de tipos diferentes (por exemplo, intervalos, ausências, dias especiais etc.) e os intervalos de tempo podem se sobrepor e / ou se cruzar.
É não , com certeza, que apenas as combinações plausíveis de intervalos de existir em dados brutos, por exemplo. intervalos de presença sobrepostos não fazem sentido, mas podem existir. Tentei identificar os intervalos de tempo de presença resultantes de várias maneiras agora - para mim, o mais confortável parece ser o seguinte.
;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";
veja SQL-Fiddle para alguns dados de demonstração.
Os dados brutos existem em tabelas diferentes na forma de "starttime" - "endtime"
ou "starttime" - "duration"
.
A idéia era obter uma lista ordenada de todos os registros de data e hora com uma soma rolante "mascarada" de intervalos abertos a cada momento para estimar o tempo de presença.
O violino funciona e fornece resultados estimados, mesmo que os tempos de início de intervalos diferentes sejam iguais. Nenhum índice é usado neste exemplo.
É este o caminho certo para realizar tarefas questionadas ou existe uma maneira mais elegante para isso?
Se relevante para responder: a quantidade de dados será de até dez mil conjuntos de dados por funcionário por tabela. O sql-2012 não está disponível para calcular uma soma contínua de predecessores in-line de forma agregada.
editar:
Apenas executou a consulta contra uma quantidade maior de dados de teste (1000, 10.000, 100.000, 1 milhão) e pode ver que o tempo de execução aumenta exponencialmente. Obviamente, uma bandeira de aviso, certo?
Alterei a consulta e removi a agregação da soma rolante por uma atualização peculiar.
Eu adicionei uma tabela auxiliar:
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" )
e mudei o cálculo da soma rolante para este local:
declare @rolSum int = 0
update "timestamps" set @rolSum = "rolSum" = @rolSum + power( 2, "type" ) * "opening" from "timestamps"
O tempo de execução diminuiu para 3 segundos em relação a 1 milhão de entradas na tabela "horário de trabalho".
A pergunta permanece a mesma : qual é a maneira mais eficaz de resolver isso?
[this]
. Eu gosto mais do que aspas duplas, eu acho.