sql >> Databasteknik >  >> RDS >> Mysql

Hur man returnerar rader som saknas i tabellen - Anställd frånvarorapport

Om en "frånvaro" definieras som att en rad inte visas i emp_tx tabell för en viss empcode för ett visst datum (datum=midnatt till midnatt 24 timmar), och ...

Om det är acceptabelt att inte visa en "frånvaro" för ett datum då det INGA transaktioner finns i emp_tx tabell för det datumet (dvs exkludera ett datum när ALLA empkoder saknas på det datumet), sedan ...

Du kan få de första fyra kolumnerna i den angivna resultatuppsättningen med en fråga som denna:(otestad)

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

Får den femte kolumnen TotalNoofAbsent returneras i samma resultatuppsättning är möjligt, men det kommer att göra den frågan riktigt rörig. Denna detalj kan hanteras mer effektivt på klientsidan när den returnerade resultatuppsättningen bearbetas.

Så fungerar frågan

Den infogade vyn alias som d ger oss en uppsättning "datum"-värden som vi kontrollerar. Använda emp_tx tabell som en källa för dessa "datum"-värden är ett bekvämt sätt att göra detta. Inte DATE() funktionen returnerar bara "date"-delen av DATETIME-argumentet; vi använder en GROUP BY för att få en distinkt lista över datum (dvs inga dubbletter av värden). (Vad vi är ute efter, med den här inbyggda vyfrågan, är en distinkt uppsättning DATE-värden mellan de två värdena som skickas in som argument. Det finns andra, mer involverade, sätt att skapa en lista med DATE-värden.)

Så länge som varje "datum"-värde som du kommer att betrakta som en "frånvaro" visas någonstans i tabellen (det vill säga minst en empcode hade en transaktion på varje datum som är av intresse), och så länge antalet rader i emp_tx Tabellen inte är överdriven, då kommer inlinevy-frågan att fungera ganska bra.

(OBS:Frågan i inlinevyn kan köras separat för att verifiera att resultaten är korrekta och som vi förväntar oss.)

Nästa steg är att ta resultaten från inline-vyn och utföra en CROSS JOIN operation (för att generera en kartesisk produkt) för att matcha VARJE empcode med VARJE date återvänt från inline-vyn. Resultatet av denna operation representerar varje möjlig förekomst av "närvaro".

Det sista steget i frågan är att utföra en "anti-join"-operation med en LEFT JOIN och en WHERE IS NULL predikat. LEFT JOIN (outer join) returnerar alla möjliga närvaroförekomster (från vänster sida), INKLUSIVE de som inte har en matchande rad (närvaropost) från emp_tx bord.

"Knepet" är att inkludera ett predikat (i WHERE-satsen) som kasserar alla rader där en matchande närvaropost hittades, så att det vi har kvar är alla kombinationer av empcode och date (möjliga närvarohändelser) där det inte fanns INGEN MATCHANDE närvarotransaktion.

(OBS:Jag har medvetet lämnat referenserna till kolumnen s_date (DATETIME) "blotta" i predikaten och använt intervallpredikat. Detta gör att MySQL effektivt kan använda ett lämpligt index som inkluderar den kolumnen.)

Om vi ​​skulle slå in kolumnreferenserna i predikaten inuti en funktion t.ex. DATE(p.s_date) , då kommer MySQL inte att kunna använda ett index effektivt på s_date kolumn.

Som en av kommentarerna (på din fråga) påpekar, gör vi ingen skillnad mellan transaktioner som markerar en anställd som antingen "kommer in" eller "går ut". Vi letar ENDAST efter förekomsten av en transaktion för den empkoden under en given 24-timmarsperiod "midnatt till midnatt".

Det finns andra tillvägagångssätt för att få samma resultatuppsättning, men "anti-join"-mönstret visar sig vanligtvis ge bäst prestanda med stora uppsättningar.

För bästa prestanda vill du troligen ha täckande index:

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

... ON emp_tx (s_date, empcode)


  1. Hur räknar man relaterade rader inklusive underkategorier?

  2. Garanterar UNION ALL ordningen på resultatuppsättningen

  3. Golang MySQL frågar efter odefinierad mängd args med IN-operatorn

  4. finns det en filstorleksgräns när man skapar en csv-fil med php och mysql?