假设我有以下数据结构:
DROP TABLE IF EXISTS `A`;
DROP TABLE IF EXISTS `B`;
DROP TABLE IF EXISTS `C`;
CREATE TABLE IF NOT EXISTS `C` (
`ID_C`
INT UNSIGNED
NOT NULL
AUTO_INCREMENT,
PRIMARY KEY (`ID_C`)
)
ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `B` (
`ID_B`
INT UNSIGNED
NOT NULL
AUTO_INCREMENT,
`REF_C`
INT UNSIGNED
NOT NULL,
PRIMARY KEY (`ID_B`),
INDEX `FK_C` (`REF_C` ASC),
CONSTRAINT `FK_C`
FOREIGN KEY (`REF_C`)
REFERENCES `C` (`ID_C`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `A` (
`ID_A`
INT UNSIGNED
NOT NULL
AUTO_INCREMENT,
`REF_B`
INT UNSIGNED
NOT NULL,
PRIMARY KEY (`ID_A`),
INDEX `FK_B` (`REF_B` ASC),
CONSTRAINT `FK_B`
FOREIGN KEY (`REF_B`)
REFERENCES `B` (`ID_B`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB;
INSERT INTO `C`
(`ID_C`)
VALUES
(NULL),
(NULL);
INSERT INTO `B`
(`ID_B`, `REF_C`)
VALUES
(NULL, 1),
(NULL, 1),
(NULL, 2),
(NULL, 2);
INSERT INTO `A`
(`ID_A`, `REF_B`)
VALUES
(NULL, 1),
(NULL, 2),
(NULL, 3),
(NULL, 4);
表B
可能有超过 3000 条记录:大约 600 条记录,引用到 table 中的不同行C
。我的服务器上启用了两个设置:
SELECT
@@SQL_SAFE_UPDATES as `safe mode`, -- result: 1
@@LOG_BIN as `binary log`; -- result: 1
问题: 如何有效地删除 table 中的所有记录,通过 tableA
引用 tableC
的记录B
而不发出警告?
我尝试了什么:
DELETE
`A`.*
FROM
`A` INNER JOIN `B` ON `REF_B` = `ID_B`
WHERE
`B`.`REF_C` = 1;
DBMS 服务器发出safe_mode
错误:
错误代码:1175。您正在使用安全更新模式,并且您尝试更新没有使用 KEY 列的 WHERE 的表 要禁用安全模式,请切换 Preferences -> SQL Queries 中的选项并重新连接。
我已删除B.
别名:
DELETE
`A`.*
FROM
`A` INNER JOIN `B` ON `REF_B` = `ID_B`
WHERE
`REF_C` = 1;
是的,它成功了,但我有这个:
2 行受影响,1 个警告:1592 使用语句格式将不安全语句写入二进制日志,因为 BINLOG_FORMAT = STATEMENT。从另一个表中选择后写入具有自动增量列的表的语句是不安全的,因为检索行的顺序决定了将写入哪些(如果有)行。此顺序无法预测,并且可能在主从服务器上有所不同。
另外,我试图强制使用 PRIMARY KEY:
DELETE
`A`.*
FROM
`A` INNER JOIN `B` ON `REF_B` = `ID_B`
WHERE
`A`.`ID_A` > 0
AND
`REF_C` = 1;
但这也没有帮助。我对我的服务器做了什么坏事或邪恶的事吗?什么方法是正确的?我错过了什么吗?
提前致谢。任何帮助将不胜感激。
PS:我知道如何使用谷歌和搜索栏。这是我发现的:
https://stackoverflow.com/questions/12275864/multiple-delete-not-working-with-inner-join
http://tech-solutions4u.blogspot.ru/2012/09/mysql-multi-delete-issue-in-safe-mode.html
等等。我已经尝试过,但最后,我不喜欢禁用服务器功能(不是由我设置的)的想法,甚至“暂时......”。
编辑:
我知道,有一种解决方法可以保存GROUP_CONCAT(ID_B)
在临时变量中并通过它的“标量”值执行删除:
SELECT GROUP_CONCAT(`ID_B`) INTO @tmp FROM `B` WHERE `REF_C` = 1;
DELETE FROM
`A`
WHERE
FIND_IN_SET(`REF_B`, @tmp)
AND
`ID_A` > 0;
但这将是近似600 * 5 = 3000
字符,所以这个想法也不受欢迎。我的意思是,如果没有其他可能,这将是最后的选择。