Найти недостающие данные MySQL - PullRequest
1 голос
/ 12 января 2012

Итак, у нас есть таблица, которая называется timePunches:

CREATE TABLE `timePunches` (
    `punchID` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'The unique ID of the punch',
    `employeeID` VARCHAR(50) NOT NULL COMMENT 'Who did the punch',
    `punchDATETIME` DATETIME NOT NULL COMMENT 'The time of the punch',
    `punchDTC_LINK` DATETIME NULL DEFAULT NULL COMMENT 'The previous start time for the OUT punch',
    `punchDATECRC` INT(100) NOT NULL COMMENT 'The punch CRC, to prevent hacking',
    `punchDIRECTION` TINYTEXT NOT NULL COMMENT 'What the punch did',
    `punchTOTAL` INT(11) NULL DEFAULT NULL,
    `fullName` TEXT NULL,
    PRIMARY KEY (`punchID`)
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM
ROW_FORMAT=DYNAMIC
AUTO_INCREMENT=15825

Эта таблица используется для отслеживания времени работы наших сотрудников. То есть мы отслеживаем, когда они пробивают в и пробивают в . Эта таблица является таблицей соответствия аудита. Это означает, что мы не SELECT / UPDATE записываем, вместо этого мы SELECT / INSERT только их.

Итак, вот что происходит, когда пользователь нажимает на часы:

  • PUNCH IN: Приложение отправляет в базу данных employeeID (строка), punchDATETIME (DateTime), punchDATECRC (int) и punchDTC_LINK (DateTime [null]) через хранимую процедуру. Эта хранимая процедура добавляет необходимую информацию в базу данных, включая запуск внутренней функции для извлечения полного имени пользователя в ту же таблицу.

  • PUNCH OUT : приложение отправляет в базу данных employeeID (строка), punchDATETIME (DateTime), punchDATECRC (int) и punchDTC_LINK (DateTime). Хранимая процедура добавляет необходимую информацию, включая триггер для выполнения математических операций между обоими элементами DateTime и заполнения допустимого имени.

Как видно из вышесказанного, когда пользователь нажимает IN , запрос выглядит примерно так:

INSERT INTO timePunches (punchID, employeeID, punchDATETIME, punchDTC_LINK, punchDATECRC, punchDIRECTION, punchTOTAL) ЗНАЧЕНИЯ (15797, 'prumple', '2012-01- 11 17:35:10 ', NULL, -2011509138,' IN ', NULL);

И, когда пользователь пробивает из , он отправляет что-то вроде этого:

INSERT INTO timePunches (punchID, employeeID, punchDATETIME, punchDTC_LINK, punchDATECRC, punchDIRECTION, punchTOTAL) ЗНАЧЕНИЯ (15797, 'prumple', '2012-01- 11 19:39:52 ',' 2012-01-11 17:35:10 ', -2011509138, «OUT», NULL);

Итак, как мы видим, в DataTable для этого пользователя есть 2 элемента. Один IN и один OUT.

Что мне нужно сделать, это выяснить, забыл ли пользователь ударить OUT. Итак, предположим, что пользователь нажимает IN, работает весь день, закрывает свои часы без ударов, а затем на следующий день снова запускает IN. Затем он работает в полную смену, и на этот раз не забивает out.

Теперь для этой ситуации у нас есть 2 IN ударов и только 1 OUT ударов. Мне нужен способ обнаружить это.

Ответы [ 4 ]

1 голос
/ 12 января 2012

Если я правильно понимаю, соответствующая запись «OUT» для записи «IN» будет соответствовать на employeeID (удар предназначен для того же сотрудника), а «IN» DATETIME будет соответствовать «OUT» DTC_LINK .

-- Fetch all 'IN' records without a corresponding 'OUT'
    SELECT tp_in.*
     FROM timePunches tp_in
LEFT JOIN timePunches tp_out
          ON tp_in.employeeID = tp_out.employeeID
             AND
             tp_in.punchDATETIME = tp_out.punchDTC_LINK
    WHERE tp_in.punchDIRECTION = 'IN'
          AND
          tp_out.punchDTC_LINK IS NULL;
1 голос
/ 12 января 2012

Вы сказали: «Видите ли, когда пользователь вводит данные, он заполняет все необходимые данные, кроме поля punchDTC_LINK; это поле остается пустым, поскольку это поле используется для предыдущего времени запуска».

Это должно означать, что вы можете просто сделать WHERE punchDIRECTION = "IN" AND punchDTC_LINK = NULL

0 голосов
/ 12 января 2012

Поскольку вы сопоставляете его с последним IN, найдите последний и добавьте к нему OUT.Но то, что я, честно говоря, не понимаю, это то, почему вы должны соответствовать IN и вне на одной записи.

Мне приходилось разрабатывать систему учета рабочего времени каждый день, чтобы мне платили, нужно было входить и выходить.Наша система хронометража имеет индивидуальный учет для каждого удара и выхода.Вы можете выполнить поиск, если текущий день имеет два IN в строке ИЛИ два OUT в строке, то происходит ошибка, или если в предыдущий день было два IN в строке ИЛИ два OUT в строке ИЛИ не начинается с и IN ИЛИне заканчивается без и OUT, тогда происходит ошибка

Обновление:

Я понимаю это, но почему он должен хранить информацию о ударе IN в линии удара?Время удара всегда всегда в последовательном порядке.Так что, если время хранит их в порядке IN IN или IN OUT, это самый простой способ узнать.

Пример того, что я предлагал сохранить в виде:

IN 2012-01-0808:00

IN 2012-01-08 11:00 AM

OUT 2012-01-08 15:00 PM

Ваш чек будет проверять, есть ли в день два IN встроки, которые в порядке времени, а также.Если вы хотите сделать это по-своему, то сопоставьте все одиночные входы с парными входами и получите несоответствующие, так что в основном вы должны сделать левое объединение ваших только в ударах с правыми входами входов сOUTs, тогда ваш список слева, имеющий нулевые значения в совпадении, покажет вам ваши ошибки.

0 голосов
/ 12 января 2012

Вы бы оставили внешнее соединение таблицы с самим собой:

select
   a.punchId
from
   timePunches a
   left outer join timePunches b on
       a.punchId = b.punchDTC_LINK
where
   b.punchDTC_LINK is null
   and a.punchDirection = 'IN';

Это вернет то, что вы ищете, я думаю.

Я отредактировал, чтобы добавить проверку для punchDirection of in.

Вы также можете изменить часть выбора, чтобы выбрать. *, Что позволит вам получить все из записи.

Дополнительные правки:

Вышеприведенный код, похоже, решил исходную проблему, но в чем реальная проблема, когда кто-то регистрируется дважды подряд, а затем проверяет. В MYSQL это невероятно сложная проблема, но в Postgres & Oracle она относительно проста и может быть решена с помощью оконных функций. Я знаю, что это не решит вашу проблему, но вы можете решить проблему с помощью сценария после свершившегося факта. В postgres / oracle следующее найдет записи, которые вы ищете:

select * from
(select
   a.punchId,
   lag(b.punchDTC_LINK,1) over (
      partition by a.employeeId
      order by a.punchDATETIME
   ) prev_link,
   a.punchDTC_LINK cur_link
from
   timePunches a
   left outer join timePunches b on
      a.punchId = b.punchDTC_LINK)
where prev_link is null and cur_link is not null;

Или что-то подобное. Я не проверял это.

Что касается скрипта, вы можете использовать следующий запрос:

select
   a.punchId,
   a.employeeID,
   a.punchDATETIME,
   a.punchDIRECTION,
   b.punchDATETIME,
   b.punchDIRECTION
from
   timePunches a
   left outer join timePunches b on
       a.punchId = b.punchDTC_LINK
order by a.employeeID, a.punchDATETIME desc;

и, зацикливая данные и / или написав скрипт для зацикливания данных и поиска мест, где b.punchDIRECTION является нулевым и это не первая запись для данного сотрудника, вы легко сможете найти плохие записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...