sql >> Base de Datos >  >> RDS >> Mysql

Cómo devolver filas que faltan en la tabla - Informe de ausencia de empleado

Si una "ausencia" se define como la no aparición de una fila en el emp_tx tabla para un empcode particular para una fecha en particular (fecha=medianoche a medianoche en un período de 24 horas) y...

Si es aceptable no mostrar una "ausencia" para una fecha cuando NO hay transacciones en el emp_tx tabla para esa fecha (es decir, excluir una fecha cuando TODOS los códigos de inserción están ausentes en esa fecha), luego...

Puede obtener las primeras cuatro columnas del conjunto de resultados especificado con una consulta como esta:(no probado)

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

Obtener esa quinta columna TotalNoofAbsent devuelto en el mismo conjunto de resultados es posible, pero hará que la consulta sea realmente complicada. Este detalle podría manejarse de manera más eficiente en el lado del cliente, al procesar el conjunto de resultados devuelto.

Cómo funciona la consulta

La vista en línea con alias como d nos obtiene un conjunto de valores de "fecha" que estamos comprobando. Usando el emp_tx table como fuente de estos valores de "fecha" es una forma conveniente de hacer esto. No el DATE() la función devuelve solo la parte de "fecha" del argumento DATETIME; estamos usando un GROUP BY para obtener una lista distinta de fechas (es decir, sin valores duplicados). (Lo que buscamos, con esta consulta de vista en línea, es un conjunto distinto de valores de FECHA entre los dos valores pasados ​​como argumentos. Hay otras formas más complejas de generar una lista de valores de FECHA).

Siempre que cada valor de "fecha" que considerará como una "ausencia" aparezca en algún lugar de la tabla (es decir, al menos un empcode tenido una transacción en cada fecha que sea de interés), y siempre que el número de filas en el emp_tx table no es excesiva, entonces la consulta de vista en línea funcionará razonablemente bien.

(NOTA:la consulta en la vista en línea se puede ejecutar por separado, para verificar que los resultados sean correctos y como esperamos).

El siguiente paso es tomar los resultados de la vista en línea y realizar una CROSS JOIN operación (para generar un producto cartesiano) para que coincida con CADA empcode con CADA date devuelto desde la vista en línea. El resultado de esta operación representa cada ocurrencia posible de "asistencia".

El paso final en la consulta es realizar una operación "anti-unión", usando un LEFT JOIN y un WHERE IS NULL predicado. El LEFT JOIN (unión externa) devuelve todas las ocurrencias de asistencia posibles (desde el lado izquierdo), INCLUYENDO aquellas que no tienen una fila coincidente (registro de asistencia) del emp_tx mesa.

El "truco" es incluir un predicado (en la cláusula WHERE) que descarte todas las filas donde se encontró un registro de asistencia coincidente, de modo que lo que nos quede sean todas las combinaciones de empcode y date (posibles ocurrencias de asistencia) donde NO hubo transacción de asistencia COINCIDENTE.

(NOTA:he dejado a propósito las referencias a la columna s_date (DATETIME) "desnudas" en los predicados y he usado predicados de rango. Esto permitirá que MySQL haga un uso efectivo de un índice apropiado que incluya esa columna).

Si tuviéramos que envolver las referencias de columna en los predicados dentro de una función, p. DATE(p.s_date) , MySQL no podrá hacer un uso efectivo de un índice en el s_date columna.

Como señala uno de los comentarios (sobre su pregunta), no estamos haciendo ninguna distinción entre las transacciones que marcan a un empleado como "entrante" o "saliente". SOLAMENTE buscamos la existencia de una transacción para ese código de inserción en un período determinado de 24 horas de "medianoche a medianoche".

Existen otros enfoques para obtener el mismo conjunto de resultados, pero el patrón "anti-unión" suele dar el mejor rendimiento con conjuntos grandes.

Para obtener el mejor rendimiento, es probable que desee cubrir índices:

... ON master (empcode, name, dept)

... ON emp_tx (s_date, empcode)