Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да върнете редове, които липсват в таблицата - Доклад за отсъствие на служител

Ако "отсъствието" е дефинирано като непоказване на ред в emp_tx таблица за конкретен empcode за определена дата (дата=24-часов период от полунощ до полунощ) и ...

Ако е приемливо да не се показва „отсъствие“ за дата, когато НЯМА транзакции в emp_tx таблица за тази дата (т.е. изключете дата, когато ВСИЧКИ empcode отсъстват на тази дата), тогава ...

Можете да получите първите четири колони от посочения набор от резултати със заявка като тази:(нетествано)

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

Получаване на тази пета колона TotalNoofAbsent върнати в същия набор от резултати е възможно, но това ще направи тази заявка наистина объркана. Тази подробност може да бъде по-ефективно обработена от страна на клиента при обработката на върнатия набор от резултати.

Как работи заявката

Вграденият изглед с псевдоним като d ни получава набор от стойности на "дата", които проверяваме. Използване на emp_tx таблицата като източник на тези стойности на "дата" е удобен начин да направите това. Не DATE() функцията връща само частта "дата" от аргумента DATETIME; ние използваме GROUP BY за да получите отделен списък с дати (т.е. без дублиращи се стойности). (Това, което преследваме, с тази заявка за вграден изглед, е отделен набор от стойности на DATE между двете стойности, предадени като аргументи. Има други, по-ангажирани начини за генериране на списък от стойности на DATE.)

Докато всяка стойност на „дата“, която смятате за „отсъствие“, се появява някъде в таблицата (т.е. поне един empcode имаше една транзакция на всяка дата, която представлява интерес), и докато броят редове в emp_tx таблица не е прекомерна, тогава заявката за вграден изглед ще работи сравнително добре.

(ЗАБЕЛЕЖКА:Заявката във вградения изглед може да се изпълнява отделно, за да се провери дали резултатите са правилни и както очакваме.)

Следващата стъпка е да вземете резултатите от вградения изглед и да извършите CROSS JOIN операция (за генериране на декартово произведение), за да съответства на ВСЕКИ empcode с ВСЯКА date върнати от вградения изглед. Резултатът от тази операция представлява всяка възможна поява на "присъствие".

Последната стъпка в заявката е да се извърши операция "анти-присъединяване", като се използва LEFT JOIN и WHERE IS NULL предикат. LEFT JOIN (външно присъединяване) връща всяко възможно събитие за присъствие (от лявата страна), ВКЛЮЧИТЕЛНО тези, които нямат съответстващ ред (запис на присъствие) от emp_tx таблица.

„Номерът“ е да включите предикат (в клаузата WHERE), който отхвърля всички редове, където е намерен съответстващ запис на присъствие, така че това, което ни остава, са всички комбинации от empcode и date (възможни случаи на присъствие), където НЯМА СЪОТВЕТСТВАЩА транзакция за присъствие.

(ЗАБЕЛЕЖКА:Нарочно оставих препратките към колоната s_date (DATETIME) „голи“ в предикатите и използвах предикати за диапазон. Това ще позволи на MySQL да използва ефективно подходящ индекс, който включва тази колона.)

Ако трябваше да обвием препратките към колони в предикатите вътре във функция, напр. DATE(p.s_date) , тогава MySQL няма да може да използва ефективно индекс на s_date колона.

Както се посочва в един от коментарите (по вашия въпрос), ние не правим никаква разлика между транзакциите, които обозначават служител като „влизащ“ или „излизащ“. Ние търсим САМО съществуването на транзакция за този empcode в даден 24-часов период от „полунощ до полунощ“.

Има и други подходи за получаване на същия набор от резултати, но моделът „против присъединяване“ обикновено се оказва, че дава най-добра производителност при големи набори.

За най-добра производителност вероятно ще искате да покривате индекси:

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

... ON emp_tx (s_date, empcode)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Защо MySQL round плава много повече от очакваното?

  2. Грешка при миграцията в django 2; AttributeError:обектът 'str' няма атрибут 'decode'

  3. MySql не работи във Visual Studio 2012:Типът или името на пространството от имена „MySql“ не може да бъде намерено

  4. Това безопасна/силна функция за дезинфекция ли е?

  5. как да игнорирам обратните отметки в codeigniter, когато използвам активни записи? трябва да поръчам по случаи