Mysql / MariaDB Триггер проблема и отладка - PullRequest
0 голосов
/ 02 ноября 2018

В настоящее время я разрабатываю услугу считывания токенов (RFID) для моего удовольствия и знаний, поверьте или нет. Я говорю по-французски лучше, чем по-английски, поэтому, пожалуйста, извинения. Гугл переводчик мой друг, но ...

Мой проект действительно прост:

  • RFID считыватель куплен по желанию
  • Веб-страница HTML с кодом RFID, читаемая
  • Ajax Query, делающий SELECT для моей таблицы t_rfids кодов для извлечения прикрепленного пользователя

  • ЕСЛИ the_users_id НЕ ПУСТО ВСТАВИТЬ запись t_accesslogs.

Это структура таблицы:

CREATE TABLE test_punch.t_accesslogs (
  id_tokenaccesslog bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  punchtime timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  id_ref_user bigint(20) UNSIGNED NOT NULL,
  PRIMARY KEY (id_tokenaccesslog)
)
ENGINE = INNODB,
CHARACTER SET latin1,
COLLATE latin1_swedish_ci;

Итак, сделав простой INSERT INTO t_accesslogs (id_ref_user) VALUES (3); я получил свою запись для CURRENT_TIMESTAMP.

Все работает хорошо, но я пытаюсь оптимизировать журналы доступа в запись временной карты с датой, time_start, time_end. Структура таблицы:

CREATE TABLE test_punch.t_timecards (
  id_timecard bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  id_ref_user bigint(20) UNSIGNED NOT NULL,
  day_date date NOT NULL,
  time_begin time NOT NULL,
  time_end time DEFAULT NULL,
  PRIMARY KEY (id_timecard)
)
ENGINE = INNODB,
CHARACTER SET latin1,
COLLATE latin1_swedish_ci;

Я пытаюсь найти лучший способ заполнить эти таблицы без использования внешних кодов, поэтому я попробую Триггеры. Есть код триггера:

CREATE 
DEFINER = 'root'@'localhost' 
TRIGGER test_punch.add_timecard_entry
    AFTER INSERT
    ON test_punch.t_accesslogs
    FOR EACH ROW
    BEGIN
      DECLARE bint_IdTimeCard BIGINT; 
      DECLARE dt_Punch DATE;
      DECLARE time_Start TIME;
      DECLARE time_End TIME;

      SELECT  t_timecards.id_timecard INTO bint_IdTimeCard 
      FROM t_timecards
      WHERE t_timecards.id_ref_user = NEW.id_ref_user 
        AND  day_date = CAST(NEW.punchtime as DATE)
        AND  time_begin IS NOT NULL
        AND  time_end IS NULL;

      IF (bint_IdTimeCard IS NOT NULL) THEN
        UPDATE t_timecards 
        SET t_timecards.time_end = CAST(NEW.punchtime AS TIME) 
        WHERE t_timecards.id_timecard=bint_IdTimeCard
          AND t_timecards.id_ref_user=NEW.id_ref_user;
      ELSE
        INSERT INTO t_timecards (id_ref_user,day_date,time_begin) 
        VALUES (NEW.id_ref_user,
                CAST(NEW.punchtime AS DATE),
                CAST(NEW.punchtime AS TIME));
      END IF;
END

Первое, что я не уверен, это значение, возвращаемое, если значение SELECT равно Null. это настоящий NULL или пустой? Как уже говорилось ранее, трудно отлаживать, даже если я использую dbForge Studio (см. Отладка триггеров MySQL )

На самом деле поведение кода не похоже на правильную обработку оператора IF. Есть идеи о том, что я делаю не так?

Любая помощь будет оценена.

Спасибо

Martin

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Спасибо за ваши комментарии. Мне было проще использовать триггер вместо хранимой процедуры, но я попробую хранимую процедуру. Дело в том, что моя таблица t_accesslogs будет и останется моей таблицей "истины". В моем подходе я не планировал добавлять / удалять записи из этих таблиц, только в таблицах t_timecards. Вероятно, мой логический должен быть обзор.

Я пытаюсь написать представление, и оно работает хорошо, за исключением того, что это убивает исключение, например, если человек "толкает" дважды по ошибке.

Вот мой код просмотра:

SELECT
    `t_accesslogs`.`id_ref_user` AS `id_user`,
    `t_accesslogs`.`dt_scan`     AS `dt_scan`,
    MIN(`t_accesslogs`.`dt_scan`) AS `dt_scan_min`,
    MAX(`t_accesslogs`.`dt_scan`) AS `dt_scan_max`
FROM `t_accesslogs`
GROUP BY CAST(`t_accesslogs`.`dt_scan` AS DATE)

Как я уже сказал, это работа, но я пытаюсь автоматизировать метку времени начала и конца. Я попробую хранимую процедуру и сообщу вам.

Спасибо

РЕДАКТИРОВАТЬ:

Хммммм странно. Используя статью об отладке, я обнаружил, что проблема заключалась в SELECT. Я изменил свое ГДЕ состояние с:

WHERE t_timecards.id_ref_user = NEW.id_ref_user 
  AND  day_date = CAST(NEW.punchtime AS DATE)
  AND  time_begin IS NOT NULL 
  AND time_end IS NULL;

по

WHERE t_timecards.id_ref_user = NEW.id_ref_user 
  AND  day_date = CAST(NEW.punchtime AS DATE)
  AND  (time_begin IS NOT NULL AND time_end IS NULL);

и это исправляет поведение. Наверное, мне нужно больше читать.

Спасибо за вашу помощь, и я преобразую свой триггер в хранимую процедуру. Вы правы, легче отлаживать.

0 голосов
/ 02 ноября 2018

Если можно: не надо. Не используйте триггеры для чего-либо подобного. Используйте триггеры только по одной причине: для сохранения ссылочной целостности. Предпочтительно, не используйте их для этого, если вам не нужно. Положитесь на DRI вместо этого.

Нет необходимости корректировать данные таким образом во время вставки. Это сделает ваше приложение более сложным и менее надежным.

Вместо этого я рекомендую посмотреть. Напишите представление, которое представляет вашу таблицу так, как вы хотите ее использовать. Посмотрите, подходит ли это вашей цели.

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

...