Mysql / MariaDB触发器问题和调试

时间:2018-11-02 14:48:44

标签: mysql triggers mariadb

我目前正在开发令牌读取器(RFID)服务,以获取我自己的乐趣和知识,无论您相信与否。我说法语比英语说得好,所以请大家保持警惕。 Google翻译是我的朋友,但是...

我的项目非常简单:

  • Wish购买的RFID阅读器
  • 接收RFID代码读取的HTML网页
  • 在我的表上执行SELECT的Ajax查询t_rfids代码以检索附加的用户

  • 如果the_users_id不为NULL,则插入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)值(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还是Empty?如前所述,即使使用dbForge Studio也很难调试(请参见Debugging MySQL Triggers

实际上,代码行为似乎无法正确处理IF语句。关于我在做什么错的任何想法吗?

任何帮助将不胜感激。

谢谢

马丁

2 个答案:

答案 0 :(得分:0)

如果可以的话,不要。请勿对此类情况使用触发器。使用触发器仅出于一个原因:维护引用完整性。最好不要使用它们,除非您必须这样做。而是依靠DRI。

插入时无需以此方式调整数据。这样做会使您的应用程序更加复杂且可靠性降低。

我推荐一个视图。编写一个表示您要使用的表的视图。看看是否适合您的目的。

如果视图执行不佳,则可能有助于保留其他表示形式。如果是这样,请使用存储过程执行要在表中插入级别高于的操作,并要求应用程序使用该存储过程。您可能会发现使用第二张表保存派生的信息很方便。

答案 1 :(得分:0)

感谢您的评论。我发现使用触发器代替存储过程更容易,但是我将尝试一下存储过程。事实是我的表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条件:

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);

,并且可以解决此问题。我想我必须阅读更多。

感谢您的帮助,我将把触发器转换为存储过程。您是对的,更容易调试。