Mysql
 sql >> Database >  >> RDS >> Mysql

Come restituire le righe mancanti dalla tabella - Rapporto di assenza del dipendente

Se un'"assenza" è definita come la non comparsa di una riga nel emp_tx tabella per un particolare empcode per una data particolare (data=da mezzanotte a mezzanotte periodo di 24 ore) e ...

Se è accettabile non mostrare un'"assenza" per una data in cui NON ci sono transazioni in emp_tx tabella per quella data (ovvero escludere una data in cui TUTTI gli empcode sono assenti in quella data), quindi ...

Puoi ottenere le prime quattro colonne del set di risultati specificato con una query come questa:(non testato)

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

Ottenere quella quinta colonna TotalNoofAbsent restituito nello stesso set di risultati è possibile, ma renderà quella query davvero disordinata. Questo dettaglio potrebbe essere gestito in modo più efficiente sul lato client, durante l'elaborazione del set di risultati restituito.

Come funziona la query

La vista in linea alias come d ci fornisce una serie di valori di "data" che stiamo controllando. Usando il emp_tx tabella come fonte di questi valori di "data" è un modo conveniente per farlo. Non il DATE() la funzione restituisce solo la parte "data" dell'argomento DATETIME; stiamo usando un GROUP BY per ottenere un elenco distinto di date (cioè nessun valore duplicato). (Quello che stiamo cercando, con questa query di visualizzazione in linea, è un insieme distinto di valori DATE tra i due valori passati come argomenti. Esistono altri modi più complicati per generare un elenco di valori DATE.)

Finché ogni valore di "data" che considererai un'"assenza" appare da qualche parte nella tabella (ovvero, almeno un empcode aveva una transazione in ogni data di interesse) e purché il numero di righe nel emp_tx tabella non è eccessiva, quindi la query di visualizzazione in linea funzionerà abbastanza bene.

(NOTA:la query nella visualizzazione in linea può essere eseguita separatamente, per verificare che i risultati siano corretti e come previsto.)

Il passaggio successivo consiste nel prendere i risultati dalla visualizzazione in linea ed eseguire un CROSS JOIN operazione (per generare un prodotto cartesiano) da abbinare a OGNI empcode con OGNI date restituito dalla vista in linea. Il risultato di questa operazione rappresenta ogni possibile occorrenza di "presenza".

Il passaggio finale della query consiste nell'eseguire un'operazione di "anti-unione", utilizzando un LEFT JOIN e un WHERE IS NULL predicato. Il LEFT JOIN (outer join) restituisce ogni possibile occorrenza di presenza (dal lato sinistro), COMPRESE quelle che non hanno una riga corrispondente (record di presenza) da emp_tx tabella.

Il "trucco" consiste nell'includere un predicato (nella clausola WHERE) che scarti tutte le righe in cui è stato trovato un record di presenza corrispondente, in modo che ciò che ci rimane siano tutte le combinazioni di empcode e date (possibili occorrenze di presenza) in cui non si è verificata alcuna transazione di presenza CORRISPONDENTE.

(NOTA:ho volutamente lasciato "nuda" i riferimenti alla colonna s_date (DATETIME) nei predicati e utilizzato i predicati dell'intervallo. Ciò consentirà a MySQL di utilizzare in modo efficace un indice appropriato che includa quella colonna.)

Se dovessimo racchiudere i riferimenti di colonna nei predicati all'interno di una funzione, ad es. DATE(p.s_date) , MySQL non sarà in grado di utilizzare efficacemente un indice su s_date colonna.

Come sottolinea uno dei commenti (sulla tua domanda), non stiamo facendo alcuna distinzione tra le transazioni che contrassegnano un dipendente come "in entrata" o "in uscita". Stiamo SOLO cercando l'esistenza di una transazione per quell'empcode in un determinato periodo di 24 ore da "mezzanotte a mezzanotte".

Esistono altri approcci per ottenere lo stesso set di risultati, ma il modello "anti-join" di solito risulta offrire le migliori prestazioni con set di grandi dimensioni.

Per ottenere le migliori prestazioni, probabilmente vorrai coprire gli indici:

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

... ON emp_tx (s_date, empcode)