Si une "absence" est définie comme la non apparition d'une ligne dans le emp_tx
table pour un empcode
particulier pour une date particulière (date=minuit à minuit période de 24 heures), et ...
S'il est acceptable de ne pas afficher une "absence" pour une date où il n'y a AUCUNE transaction dans le emp_tx
table pour cette date (c'est-à-dire exclure une date où TOUS les empcodes sont absents à cette date), puis ...
Vous pouvez obtenir les quatre premières colonnes du jeu de résultats spécifié avec une requête comme celle-ci :(non testé)
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
Obtenir cette cinquième colonne TotalNoofAbsent
renvoyé dans le même jeu de résultats est possible, mais cela va rendre cette requête vraiment désordonnée. Ce détail peut être géré plus efficacement côté client, lors du traitement de l'ensemble de résultats renvoyé.
Fonctionnement de la requête
La vue en ligne alias d
nous obtient un ensemble de valeurs "date" que nous vérifions. Utilisation du emp_tx
table comme source de ces valeurs de "date" est un moyen pratique de le faire. Pas le DATE()
la fonction renvoie uniquement la partie "date" de l'argument DATETIME ; nous utilisons un GROUP BY
pour obtenir une liste distincte de dates (c'est-à-dire sans valeurs en double). (Ce que nous recherchons, avec cette requête de vue en ligne, est un ensemble distinct de valeurs DATE entre les deux valeurs transmises en tant qu'arguments. Il existe d'autres moyens, plus complexes, de générer une liste de valeurs DATE.)
Tant que chaque valeur "date" que vous considérerez comme une "absence" apparaît quelque part dans le tableau (c'est-à-dire au moins un empcode
avait une transaction à chaque date qui nous intéresse), et tant que le nombre de lignes dans le emp_tx
table n'est pas excessif, alors la requête de vue en ligne fonctionnera raisonnablement bien.
(REMARQUE :La requête dans la vue en ligne peut être exécutée séparément, pour vérifier que les résultats sont corrects et conformes à nos attentes.)
L'étape suivante consiste à prendre les résultats de la vue en ligne et à effectuer un CROSS JOIN
opération (pour générer un produit cartésien) pour correspondre à CHAQUE empcode
avec CHAQUE date
renvoyé de la vue en ligne. Le résultat de cette opération représente toutes les occurrences possibles de "présence".
La dernière étape de la requête consiste à effectuer une opération "anti-jointure", en utilisant un LEFT JOIN
et un WHERE IS NULL
prédicat. Le LEFT JOIN
(jointure externe) renvoie toutes les occurrences de présence possibles (à partir du côté gauche), Y COMPRIS celles qui n'ont pas de ligne correspondante (enregistrement de présence) du emp_tx
tableau.
L '"astuce" consiste à inclure un prédicat (dans la clause WHERE) qui supprime toutes les lignes où un enregistrement de présence correspondant a été trouvé, de sorte qu'il nous reste toutes les combinaisons de empcode
et date
(occurrences de présence possibles) où il n'y avait AUCUNE transaction de présence CORRESPONDANTE.
(REMARQUE :j'ai délibérément laissé les références à la colonne s_date (DATETIME) "nues" dans les prédicats et j'ai utilisé des prédicats de plage. Cela permettra à MySQL d'utiliser efficacement un index approprié qui inclut cette colonne.)
Si nous devions envelopper les références de colonne dans les prédicats à l'intérieur d'une fonction, par exemple. DATE(p.s_date)
, MySQL ne pourra pas utiliser efficacement un index à la s_date
colonne.
Comme le souligne l'un des commentaires (sur votre question), nous ne faisons aucune distinction entre les transactions qui marquent un employé comme "entrant" ou "sortant". Nous recherchons UNIQUEMENT l'existence d'une transaction pour cet empcode dans une période donnée de 24 heures "de minuit à minuit".
Il existe d'autres approches pour obtenir le même ensemble de résultats, mais le modèle "anti-jointure" s'avère généralement donner les meilleures performances avec de grands ensembles.
Pour de meilleures performances, vous souhaiterez probablement couvrir les index :
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)