使用复合主键更新后的 MySQL 触发器失败

MySQL trigger after update with composite primary key is failing

提问人:A. Cedano 提问时间:11/3/2023 更新时间:11/3/2023 访问量:25

问:

我想将更改保存到我的远程表中,以便与 Android 应用程序同步。

包含数据的表定义为:

CREATE TABLE `lh_psalm_join` (
  `groupFK` int(11) NOT NULL,
  `readingFK` int(11) NOT NULL,
  `theOrder` int(11) NOT NULL,
  `themeFK` int(11) DEFAULT NULL,
  `epigraphFK` int(11) DEFAULT NULL,
  `thePart` int(11) DEFAULT NULL,
  PRIMARY KEY (`groupFK`,`readingFK`),
  KEY `readingFK` (`readingFK`),
  KEY `epigraphFK` (`epigraphFK`),
  KEY `themeFK` (`themeFK`),
  CONSTRAINT `lh_psalm_join_ibfk_1` FOREIGN KEY (`groupFK`) REFERENCES `lh_psalmody_join` (`groupID`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `lh_psalm_join_ibfk_2` FOREIGN KEY (`readingFK`) REFERENCES `lh_psalm` (`psalmID`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `lh_psalm_join_ibfk_3` FOREIGN KEY (`epigraphFK`) REFERENCES `lh_epigraph` (`epigraphID`) ON DELETE SET NULL ON UPDATE CASCADE,
  CONSTRAINT `lh_psalm_join_ibfk_4` FOREIGN KEY (`themeFK`) REFERENCES `lh_theme` (`themeID`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci

这是 sincronization 的表格:

CREATE TABLE `sync_lh_psalm_join` (
  `groupFK` int(11) NOT NULL,
  `readingFK` int(11) NOT NULL,
  `crud` char(1) DEFAULT NULL,
  `lastUpdate` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
  PRIMARY KEY (`groupFK`,`readingFK`),
  CONSTRAINT `sync_lh_psalm_join_ibfk_1` FOREIGN KEY (`groupFK`, `readingFK`) REFERENCES `lh_psalm_join` (`groupFK`, `readingFK`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci

当插入或更新行时,我想保存引用以通过检查字段来进行同步。lh_psalm_joinsync_lh_psalm_joinlastUpdate

为此,我定义了这个 TRIGGER:

DROP TRIGGER IF EXISTS `lh_psalm_join_after_update`;
DELIMITER $$
CREATE TRIGGER `lh_psalm_join_after_update` AFTER UPDATE ON `lh_psalm_join` FOR EACH ROW
BEGIN
  DECLARE countRows INT(11) DEFAULT 0;
  SELECT 
    COUNT(*) 
  FROM `sync_lh_psalm_join` 
  WHERE 
    `groupFK`=NEW.`groupFK` AND 
    `readingFK`=NEW.`readingFK` 
  INTO countRows;
  IF countRows>0 THEN
    UPDATE `sync_lh_psalm_join` SET 
      `groupFK`=NEW.`groupFK`,
      `readingFK`=NEW.`readingFK`,
      `crud`='u', 
      `lastUpdate`=CURRENT_TIMESTAMP 
    WHERE 
      `groupFK`=OLD.`groupFK` AND 
      `readingFK`=OLD.`readingFK`;
  ELSE
    INSERT INTO `sync_lh_psalm_join` 
      (`groupFK`,`readingFK`,`crud`) 
    VALUES
      (NEW.`groupFK`,NEW.`readingFK`,'u');
  END IF;
  CALL spUpdateSyncStatus('lh_psalm_join');
END$$
DELIMITER ;

由于可能已经存在带有主键的记录,因此我的想法是将该记录更改为主键的新值(以防更新),并将列的值更改为 .lastUpdateCURRENT_TIMESTAMP

但它不起作用,如果我尝试某个主键已经存在的行的 in,它会给我这个错误:UPDATElh_psalm_joinsync_lh_psalm_join

无法删除或更新父行:外键约束失败 (., 约束外键 (, ) 参考文献 (,c39b075_deiverbusync_lh_psalm_joinsync_lh_psalm_join_ibfk_1groupFKreadingFKlh_psalm_joingroupFKreadingFK))

如果我将错误更改为:WHERE

    WHERE 
      `groupFK`=NEW.`groupFK` AND 
      `readingFK`=NEW.`readingFK`;

我的方法有什么问题?

MySQL 触发同步

评论


答:

1赞 Bill Karwin 11/3/2023 #1

该错误与您的触发器无关。如果没有触发器,并且尝试更新另一个表所依赖的主键,则会出现相同的错误。

外键的默认操作包括 ,这与 InnoDB 相同。这意味着,如果有人尝试更新子行引用的主键,则会出现错误。更新被阻止,调用方收到错误。ON UPDATE RESTRICTON UPDATE NO ACTION

这就像你在看报纸,你的伴侣在看着你的肩膀。你去翻页,你的伴侣伸出手阻止你这样做,因为他们还在阅读当前页面。:-)

其他引用操作包括 ,这似乎是您想要的。它将以原子方式将新的主键值复制到子表中。父行和子行中的值将同时更改,并且没有错误。ON UPDATE CASCADE

有关这些选项的更多信息,请阅读 https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html#foreign-key-referential-actions

您必须以这种方式声明外键:

CREATE TABLE `sync_lh_psalm_join` (
  ...
  CONSTRAINT `sync_lh_psalm_join_ibfk_1` FOREIGN KEY (`groupFK`, `readingFK`) 
    REFERENCES `lh_psalm_join` (`groupFK`, `readingFK`) ON UPDATE CASCADE
);

因此,对于您的触发器,如果您使用 INSERT...在重复密钥更新时。

CREATE TRIGGER `lh_psalm_join_after_update` AFTER UPDATE ON `lh_psalm_join` FOR EACH ROW
BEGIN
  INSERT INTO `sync_lh_psalm_join` 
    (`groupFK`,`readingFK`,`crud`) 
  VALUES
    (NEW.`groupFK`,NEW.`readingFK`,'u')
  ON DUPLICATE KEY UPDATE `crud`='u', lastUpdate=CURRENT_TIMESTAMP;
  CALL spUpdateSyncStatus('lh_psalm_join');
END$$

键列应通过声明外键来自动更新。ON UPDATE CASCADE

阅读 https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html 以获取有关 的更多信息。INSERT...ON DUPLICATE KEY UPDATE