Als een "afwezigheid" wordt gedefinieerd als het niet verschijnen van een rij in de emp_tx
tabel voor een bepaalde empcode
voor een bepaalde datum (datum=middernacht tot 24 uur per dag), en ...
Als het acceptabel is om geen "afwezigheid" te tonen voor een datum waarop er GEEN transacties zijn in de emp_tx
tabel voor die datum (d.w.z. sluit een datum uit waarop ALLE empcodes op die datum afwezig zijn), dan ...
U kunt de eerste vier kolommen van de opgegeven resultatenset krijgen met een query als deze:(niet getest)
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
Die vijfde kolom krijgen TotalNoofAbsent
geretourneerd in dezelfde resultatenset is mogelijk, maar het zal die query echt rommelig maken. Dit detail kan efficiënter worden afgehandeld aan de kant van de klant, bij het verwerken van de geretourneerde resultatenset.
Hoe de zoekopdracht werkt
De inline-weergave met de alias d
geeft ons een reeks "datum" -waarden die we controleren. De emp_tx
. gebruiken tabel als een bron van deze "datum"-waarden is een handige manier om dit te doen. Niet de DATE()
functie retourneert alleen het "datum"-gedeelte van het DATETIME-argument; we gebruiken een GROUP BY
om een duidelijke lijst met datums te krijgen (d.w.z. geen dubbele waarden). (Wat we met deze inline view-query zoeken, is een afzonderlijke set DATE-waarden tussen de twee waarden die als argumenten worden doorgegeven. Er zijn andere, meer betrokken manieren om een lijst met DATE-waarden te genereren.)
Zolang elke "datum"-waarde die u als een "afwezigheid" beschouwt, ergens in de tabel voorkomt (dat wil zeggen, ten minste één empcode
op elke interessante datum één transactie had), en zolang het aantal rijen in de emp_tx
tabel niet overdreven is, dan zal de inline view-query redelijk goed werken.
(OPMERKING:de zoekopdracht in de inline-weergave kan afzonderlijk worden uitgevoerd om te controleren of de resultaten correct zijn en zoals we verwachten.)
De volgende stap is om de resultaten uit de inline-weergave te halen en een CROSS JOIN
uit te voeren. bewerking (om een Cartesiaans product te genereren) die overeenkomt met ELKE empcode
met ELKE date
geretourneerd vanuit de inline-weergave. Het resultaat van deze bewerking vertegenwoordigt elk mogelijk optreden van "aanwezigheid".
De laatste stap in de query is het uitvoeren van een "anti-join"-bewerking met behulp van een LEFT JOIN
en een WHERE IS NULL
predikaat. De LEFT JOIN
(outer join) retourneert alle mogelijke aanwezigheidsexemplaren (vanaf de linkerkant), INCLUSIEF diegene die geen overeenkomende rij hebben (aanwezigheidsrecord) uit de emp_tx
tafel.
De "truc" is om een predikaat op te nemen (in de WHERE-clausule) dat alle rijen negeert waar een overeenkomend aanwezigheidsrecord is gevonden, zodat we alleen nog maar combinaties van empcode
overhouden. en date
(mogelijke aanwezigheidsgebeurtenissen) waar er GEEN OVEREENKOMENDE aanwezigheidstransactie was.
(OPMERKING:ik heb met opzet de verwijzingen naar de kolom s_date (DATETIME) in de predikaten "kaal" gelaten en bereikpredikaten gebruikt. Hierdoor kan MySQL effectief gebruik maken van een geschikte index die die kolom bevat.)
Als we de kolomverwijzingen in de predikaten in een functie zouden wikkelen, b.v. DATE(p.s_date)
, dan kan MySQL geen effectief gebruik maken van een index op de s_date
kolom.
Zoals een van de opmerkingen (op uw vraag) aangeeft, maken we geen onderscheid tussen transacties die een werknemer markeren als "binnenkomen" of "uitgaan". We zijn ALLEEN op zoek naar het bestaan van een transactie voor die empcode in een bepaalde periode van 24 uur 'middernacht tot middernacht'.
Er zijn andere benaderingen om dezelfde resultatenset te krijgen, maar het "anti-join"-patroon blijkt meestal de beste prestaties te geven bij grote sets.
Voor de beste prestaties wilt u waarschijnlijk indexen afdekken:
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)