Se uma "ausência" for definida como o não aparecimento de uma linha no
emp_tx
tabela para um determinado empcode
para uma data específica (data=meia-noite à meia-noite, período de 24 horas), e ... Se for aceitável não mostrar uma "ausência" para uma data em que NÃO há transações no
emp_tx
table para essa data (ou seja, exclua uma data em que TODOS os empcodes estejam ausentes nessa data), então ... Você pode obter as primeiras quatro colunas do conjunto de resultados especificado com uma consulta como esta:(não testado)
SELECT m.empcode AS `EmpCode`
, m.name AS `EmpName`
, m.dept AS `Department`
, d.dt AS `AbsentDate`
FROM ( SELECT DATE(t.s_date) AS dt
FROM emp_tx t
WHERE t.s_date >= '2012-12-12'
AND t.s_date < DATE_ADD( '2012-12-20' ,INTERVAL 1 DAY)
GROUP BY DATE(t.s_date)
ORDER BY DATE(t.s_date)
) d
CROSS
JOIN master m
LEFT
JOIN emp_tx p
ON p.s_date >= d.dt
AND p.s_date < d.dt + INTERVAL 1 DAY
AND p.empcode = m.empcode
WHERE p.empcode IS NULL
ORDER
BY m.empcode
, d.dt
Obtendo a quinta coluna
TotalNoofAbsent
retornado no mesmo conjunto de resultados é possível, mas tornará essa consulta muito confusa. Esse detalhe pode ser tratado com mais eficiência no lado do cliente, ao processar o conjunto de resultados retornado. Como a consulta funciona
A visualização em linha alias como
d
nos obtém um conjunto de valores de "data" que estamos verificando. Usando o emp_tx
table como fonte desses valores de "data" é uma maneira conveniente de fazer isso. Não é o DATE()
a função está retornando apenas a parte "data" do argumento DATETIME; estamos usando um GROUP BY
para obter uma lista distinta de datas (ou seja, sem valores duplicados). (O que buscamos, com esta consulta de visualização inline, é um conjunto distinto de valores DATE entre os dois valores passados como argumentos. Existem outras maneiras mais complicadas de gerar uma lista de valores DATE.) Contanto que cada valor de "data" que você considere como uma "ausência" apareça em algum lugar na tabela (ou seja, pelo menos um
empcode
tinha uma transação em cada data de interesse), e contanto que o número de linhas no emp_tx
table não for excessivo, então a consulta de visualização inline funcionará razoavelmente bem. (OBSERVAÇÃO:A consulta na visualização embutida pode ser executada separadamente, para verificar se os resultados estão corretos e como esperamos.)
O próximo passo é pegar os resultados da visualização inline e executar um
CROSS JOIN
operação (para gerar um produto cartesiano) para corresponder a TODOS os empcode
com TODAS as date
retornado da exibição em linha. O resultado desta operação representa todas as ocorrências possíveis de "presença". A etapa final da consulta é realizar uma operação "anti-join", usando um
LEFT JOIN
e um WHERE IS NULL
predicado. O LEFT JOIN
(junção externa) retorna todas as ocorrências de presença possíveis (do lado esquerdo), INCLUINDO aquelas que não possuem uma linha correspondente (registro de presença) do emp_tx
tabela. O "truque" é incluir um predicado (na cláusula WHERE) que descarta todas as linhas em que um registro de presença correspondente foi encontrado, de modo que o que resta são todas as combinações de
empcode
e date
(possíveis ocorrências de atendimento) onde NÃO houve transação de atendimento CORRESPONDENTE. (OBSERVAÇÃO:deixei propositalmente as referências à coluna s_date (DATETIME) "bare" nos predicados e usei predicados de intervalo. Isso permitirá que o MySQL faça uso efetivo de um índice apropriado que inclua essa coluna.)
Se fôssemos envolver as referências de coluna nos predicados dentro de uma função, por exemplo.
DATE(p.s_date)
, o MySQL não poderá fazer uso efetivo de um índice no s_date
coluna. Como um dos comentários (sobre sua pergunta) aponta, não estamos fazendo nenhuma distinção entre transações que marcam um funcionário como "entrando" ou "saindo". Estamos APENAS procurando a existência de uma transação para esse empcode em um determinado período de "meia-noite à meia-noite" de 24 horas.
Existem outras abordagens para obter o mesmo conjunto de resultados, mas o padrão "anti-junção" geralmente fornece o melhor desempenho com conjuntos grandes.
Para obter o melhor desempenho, você provavelmente desejará cobrir índices:
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)