sql >> Databáze >  >> RDS >> Mysql

Jak vrátit řádky, které v tabulce chybí - Zpráva o nepřítomnosti zaměstnance

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)


  1. Převeďte z MySQL datetime do jiného formátu pomocí PHP

  2. Jak vyvolat výjimku uvnitř spouštěče? Existuje způsob, jak to udělat?

  3. Psycopg / Postgres :Spojení se setkávají náhodně

  4. Jak rychle zrušit vnoření 2D pole do 1D pole v PostgreSQL?