Pokud je "absence" definována jako neobjevení se řádku v emp_tx
tabulka pro konkrétní empcode
pro konkrétní datum (datum=od půlnoci do půlnoci 24 hodin) a ...
Pokud je přijatelné nezobrazovat "nepřítomnost" pro datum, kdy v emp_tx
nejsou ŽÁDNÉ transakce tabulky pro toto datum (tj. vyloučit datum, kdy v dané datum chybí VŠECHNY empkódy), pak ...
První čtyři sloupce zadané sady výsledků můžete získat dotazem, jako je tento:(netestováno)
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
Získání pátého sloupce TotalNoofAbsent
vrácené ve stejné množině výsledků je možné, ale tento dotaz bude opravdu chaotický. Tento detail může být efektivněji zpracován na straně klienta při zpracování vrácené sady výsledků.
Jak dotaz funguje
Vložený pohled s aliasem d
nám získá sadu hodnot „datum“, které kontrolujeme. Pomocí emp_tx
tabulka jako zdroj těchto hodnot "datum" je pohodlný způsob, jak toho dosáhnout. Ne DATE()
funkce vrací pouze "datum" část argumentu DATETIME; používáme GROUP BY
abyste získali zřetelný seznam dat (tj. žádné duplicitní hodnoty). (To, o co nám jde v tomto dotazu na inline zobrazení, je odlišná množina hodnot DATE mezi dvěma hodnotami předanými jako argumenty. Existují další, složitější způsoby generování seznamu hodnot DATE.)
Pokud se každá hodnota „datum“, kterou budete považovat za „nepřítomnost“, objeví někde v tabulce (tj. alespoň jeden empcode
měl v každé datum jednu transakci, která je zajímavá), a pokud je počet řádků v emp_tx
tabulka není přehnaná, pak bude dotaz vloženého zobrazení fungovat přiměřeně dobře.
(POZNÁMKA:Dotaz v inline zobrazení lze spustit samostatně, aby se ověřilo, že výsledky jsou správné a jak očekáváme.)
Dalším krokem je převzít výsledky z inline zobrazení a provést CROSS JOIN
operace (pro generování kartézského součinu), aby odpovídaly KAŽDÉMU empcode
s KAŽDÝM date
se vrátil z inline zobrazení. Výsledek této operace představuje každý možný výskyt "docházky".
Posledním krokem v dotazu je provedení operace "anti-join" pomocí LEFT JOIN
a WHERE IS NULL
predikát. LEFT JOIN
(vnější spojení) vrátí všechny možné výskyty docházky (z levé strany), VČETNĚ těch, které nemají odpovídající řádek (záznam docházky) z emp_tx
tabulka.
"Trik" je vložit predikát (do klauzule WHERE), který zahodí všechny řádky, kde byl nalezen odpovídající záznam docházky, takže nám zbydou všechny kombinace empcode
a date
(možné výskyty docházky), kde neexistovala ŽÁDNÁ ODPOVÍDAJÍCÍ transakce docházky.
(POZNÁMKA:Odkazy na sloupec s_date (DATETIME) jsem záměrně ponechal v predikátech „holé“ a použil jsem predikáty rozsahu. To umožní MySQL efektivně využít vhodný index, který tento sloupec obsahuje.)
Pokud bychom zabalili odkazy na sloupce do predikátů uvnitř funkce, např. DATE(p.s_date)
, pak MySQL nebude moci efektivně využívat index v s_date
sloupec.
Jak zdůrazňuje jeden z komentářů (k vaší otázce), neděláme žádné rozdíly mezi transakcemi, které označují zaměstnance buď jako „přichází“ nebo „odchází“. Hledáme POUZE existenci transakce pro tento empkód v daném 24hodinovém období „od půlnoci do půlnoci“.
Existují i jiné přístupy, jak získat stejnou sadu výsledků, ale vzor "anti-join" obvykle poskytuje nejlepší výkon s velkými sadami.
Chcete-li dosáhnout nejlepšího výkonu, pravděpodobně budete chtít pokrýt indexy:
... ON master (empcode, name, dept)
... ON emp_tx (s_date, empcode)