Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como retornar as linhas que estão faltando na tabela - Relatório de Ausência do Funcionário


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)