Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment renvoyer des lignes manquantes dans le tableau - Rapport d'absence des employés

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)