我想将更改保存到我的远程表中,以便与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_join中插入或更新一行时,我希望在sync_lh_psalm_join中保存一个引用,以便通过判断lastUpdate字段来执行同步.

为此,我定义了这个触发器:

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 ;

由于可能已经存在具有主键的记录,我的 idea 是在更新时将该记录更改为主键的新值,并将lastUpdate列的值更改为CURRENT_TIMESTAMP.

但它不起作用,如果我try 主键已经存在于sync_lh_psalm_join中的某行的lh_psalm_join中的UPDATE,它会给我这个错误:

无法删除或更新父行:外键约束失败 (c39b075_deiverbu.sync_lh_psalm_join,约束 sync_lh_psalm_join_ibfk_1 FOREIGN KEY(groupFKreadingFK) 参考文献lh_psalm_join(groupFKreadingFK))

如果我将WHERE更改为:

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

我的方法有什么问题吗?

推荐答案

该错误与您的触发器无关.如果没有触发器,并且您try 更新另一个表所依赖的主键,则会得到相同的错误.

外键的默认操作为ON UPDATE RESTRICT,与InnoDB的ON UPDATE NO ACTION相同.这意味着,如果有人试图更新子行引用的主键,则是错误的.更新被阻止,调用方收到错误.

这就像你在看报纸,而你的伴侣在背后看着你.你go 翻一页,你的伴侣伸出他们的手阻止你这样做,因为他们还在阅读当前的页面.:-)

其他参考行为包括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来自动更新键列.

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

Mysql相关问答推荐

如何有效地计算共同的朋友/追随者?

SQL中的搜索模式

从 NextJS/Prisma 添加用户 ID (FK) 到 MySQL 表

使用Workbench时如何添加mysqldump配置标志

for each 查询设置 MySQL @@session.time_zone 而不是 CONVERT_TZ 的缺点?

SQL: Select TEXT 字段的子字符串比整个值快

错误1075:表定义不正确;只能有一个自动列,它必须定义为一个键(使用 gorm 和 mysql)

如果我创建一个没有主键的表然后添加一个主键,主键是聚集索引吗?

如何在 SQL 的计算列中显示小数点后两位?

如何使用nodejs从mysql数据库中获取最新的10条记录?

你如何在 Node.js 中模拟 MySQL(没有 ORM)?

索引和多列主键

如何在sequelize中定义多列的唯一索引

基于字符串动态创建 PHP 对象

MySQL - 表'my_table'没有被锁定表锁定

MySQL行格式:固定和动态之间的区别?

MySQL 连接运算符

更改 Laravel 的 created_at 和 updated_at 的名称

MySQLgo 除非数字字符进行比较

MySql 两个时间戳之间的天数差异?