我有一组InnoDB
表,需要定期删除一些行并插入其他表来进行维护。其中一些表具有引用其他表的外键约束,因此这意味着表加载顺序很重要。要插入新行而不用担心表的顺序,我使用:
SET FOREIGN_KEY_CHECKS=0;
之前,然后:
SET FOREIGN_KEY_CHECKS=1;
后。
加载完成后,我想检查更新后的表中的数据是否仍具有参照完整性-新行不会破坏外键约束-但似乎没有办法做到这一点。
作为测试,我输入了肯定违反外键约束的数据,并且在重新启用外键检查后,mysql没有产生警告或错误。
如果我试图找到一种指定表加载顺序的方法,并在加载过程中保留了外键检查功能,那么这将不允许我在具有自引用外键约束的表中加载数据,因此不是一个可以接受的解决方案。
有什么方法可以强制InnoDB验证表或数据库的外键约束?
DELIMITER $$
DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS$$
CREATE
PROCEDURE `ANALYZE_INVALID_FOREIGN_KEYS`(
checked_database_name VARCHAR(64),
checked_table_name VARCHAR(64),
temporary_result_table ENUM('Y', 'N'))
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE TABLE_SCHEMA_VAR VARCHAR(64);
DECLARE TABLE_NAME_VAR VARCHAR(64);
DECLARE COLUMN_NAME_VAR VARCHAR(64);
DECLARE CONSTRAINT_NAME_VAR VARCHAR(64);
DECLARE REFERENCED_TABLE_SCHEMA_VAR VARCHAR(64);
DECLARE REFERENCED_TABLE_NAME_VAR VARCHAR(64);
DECLARE REFERENCED_COLUMN_NAME_VAR VARCHAR(64);
DECLARE KEYS_SQL_VAR VARCHAR(1024);
DECLARE done INT DEFAULT 0;
DECLARE foreign_key_cursor CURSOR FOR
SELECT
`TABLE_SCHEMA`,
`TABLE_NAME`,
`COLUMN_NAME`,
`CONSTRAINT_NAME`,
`REFERENCED_TABLE_SCHEMA`,
`REFERENCED_TABLE_NAME`,
`REFERENCED_COLUMN_NAME`
FROM
information_schema.KEY_COLUMN_USAGE
WHERE
`CONSTRAINT_SCHEMA` LIKE checked_database_name AND
`TABLE_NAME` LIKE checked_table_name AND
`REFERENCED_TABLE_SCHEMA` IS NOT NULL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
IF temporary_result_table = 'N' THEN
DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS;
DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS;
CREATE TABLE INVALID_FOREIGN_KEYS(
`TABLE_SCHEMA` VARCHAR(64),
`TABLE_NAME` VARCHAR(64),
`COLUMN_NAME` VARCHAR(64),
`CONSTRAINT_NAME` VARCHAR(64),
`REFERENCED_TABLE_SCHEMA` VARCHAR(64),
`REFERENCED_TABLE_NAME` VARCHAR(64),
`REFERENCED_COLUMN_NAME` VARCHAR(64),
`INVALID_KEY_COUNT` INT,
`INVALID_KEY_SQL` VARCHAR(1024)
);
ELSEIF temporary_result_table = 'Y' THEN
DROP TEMPORARY TABLE IF EXISTS INVALID_FOREIGN_KEYS;
DROP TABLE IF EXISTS INVALID_FOREIGN_KEYS;
CREATE TEMPORARY TABLE INVALID_FOREIGN_KEYS(
`TABLE_SCHEMA` VARCHAR(64),
`TABLE_NAME` VARCHAR(64),
`COLUMN_NAME` VARCHAR(64),
`CONSTRAINT_NAME` VARCHAR(64),
`REFERENCED_TABLE_SCHEMA` VARCHAR(64),
`REFERENCED_TABLE_NAME` VARCHAR(64),
`REFERENCED_COLUMN_NAME` VARCHAR(64),
`INVALID_KEY_COUNT` INT,
`INVALID_KEY_SQL` VARCHAR(1024)
);
END IF;
OPEN foreign_key_cursor;
foreign_key_cursor_loop: LOOP
FETCH foreign_key_cursor INTO
TABLE_SCHEMA_VAR,
TABLE_NAME_VAR,
COLUMN_NAME_VAR,
CONSTRAINT_NAME_VAR,
REFERENCED_TABLE_SCHEMA_VAR,
REFERENCED_TABLE_NAME_VAR,
REFERENCED_COLUMN_NAME_VAR;
IF done THEN
LEAVE foreign_key_cursor_loop;
END IF;
SET @from_part = CONCAT('FROM ', '`', TABLE_SCHEMA_VAR, '`.`', TABLE_NAME_VAR, '`', ' AS REFERRING ',
'LEFT JOIN `', REFERENCED_TABLE_SCHEMA_VAR, '`.`', REFERENCED_TABLE_NAME_VAR, '`', ' AS REFERRED ',
'ON (REFERRING', '.`', COLUMN_NAME_VAR, '`', ' = ', 'REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ') ',
'WHERE REFERRING', '.`', COLUMN_NAME_VAR, '`', ' IS NOT NULL ',
'AND REFERRED', '.`', REFERENCED_COLUMN_NAME_VAR, '`', ' IS NULL');
SET @full_query = CONCAT('SELECT COUNT(*) ', @from_part, ' INTO @invalid_key_count;');
PREPARE stmt FROM @full_query;
EXECUTE stmt;
IF @invalid_key_count > 0 THEN
INSERT INTO
INVALID_FOREIGN_KEYS
SET
`TABLE_SCHEMA` = TABLE_SCHEMA_VAR,
`TABLE_NAME` = TABLE_NAME_VAR,
`COLUMN_NAME` = COLUMN_NAME_VAR,
`CONSTRAINT_NAME` = CONSTRAINT_NAME_VAR,
`REFERENCED_TABLE_SCHEMA` = REFERENCED_TABLE_SCHEMA_VAR,
`REFERENCED_TABLE_NAME` = REFERENCED_TABLE_NAME_VAR,
`REFERENCED_COLUMN_NAME` = REFERENCED_COLUMN_NAME_VAR,
`INVALID_KEY_COUNT` = @invalid_key_count,
`INVALID_KEY_SQL` = CONCAT('SELECT ',
'REFERRING.', '`', COLUMN_NAME_VAR, '` ', 'AS "Invalid: ', COLUMN_NAME_VAR, '", ',
'REFERRING.* ',
@from_part, ';');
END IF;
DEALLOCATE PREPARE stmt;
END LOOP foreign_key_cursor_loop;
END$$
DELIMITER ;
CALL ANALYZE_INVALID_FOREIGN_KEYS('%', '%', 'Y');
DROP PROCEDURE IF EXISTS ANALYZE_INVALID_FOREIGN_KEYS;
SELECT * FROM INVALID_FOREIGN_KEYS;
您可以使用此存储过程来检查所有数据库中是否有无效的外键。结果将被加载到INVALID_FOREIGN_KEYS
表中。参数ANALYZE_INVALID_FOREIGN_KEYS
:
结果是否将是暂时的。它可以是:'Y'
,'N'
,NULL
。
'Y'
该ANALYZE_INVALID_FOREIGN_KEYS
结果表会临时表。临时表对于其他会话将不可见。您可以ANALYZE_INVALID_FOREIGN_KEYS(...)
与临时结果表并行执行多个存储过程。'N'
,然后SELECT * FROM INVALID_FOREIGN_KEYS;
从另一个会话执行。NULL
跳过事务中结果表的创建,因为MySQL在CREATE TABLE ...
和中在事务中执行隐式提交DROP TABLE ...
,因此结果表的创建将在事务中引起问题。在这种情况下,您必须自己创建结果表BEGIN; COMMIT/ROLLBACK;
: CREATE TABLE INVALID_FOREIGN_KEYS(
`TABLE_SCHEMA` VARCHAR(64),
`TABLE_NAME` VARCHAR(64),
`COLUMN_NAME` VARCHAR(64),
`CONSTRAINT_NAME` VARCHAR(64),
`REFERENCED_TABLE_SCHEMA` VARCHAR(64),
`REFERENCED_TABLE_NAME` VARCHAR(64),
`REFERENCED_COLUMN_NAME` VARCHAR(64),
`INVALID_KEY_COUNT` INT,
`INVALID_KEY_SQL` VARCHAR(1024)
);
访问有关隐式提交的MySQL网站:http : //dev.mysql.com/doc/refman/5.6/en/implicit-
commit.html
这些
INVALID_FOREIGN_KEYS
行将仅包含无效数据库,表,列的名称。但是您会看到无效的引用行INVALID_KEY_SQL
以及INVALID_FOREIGN_KEYS
是否存在column的value的执行。
如果引用列(又称外部索引)和引用列(通常是主键)上都有索引,则此存储过程将非常快。
我如何测试多个。包括与在我的if语句?下面的代码似乎对一个项目有效,即。,但忽略了第二个。
问题内容: 如何用一个或多个空格或制表符爆炸字符串? 例: 我想使它成为一个数组。 问题答案:
问题内容: 我正在开发一个将用作其他应用程序的可扩展框架的应用程序。 基本类之一称为节点,节点具有内容。SQL表如下所示: TABLE节点(NodeId int,....等) 表格NodeContentRelationship(NodeId int,ContentType字符串,ContentId int) 开发人员可以扩展应用程序以创建自己的内容类型。 显然,从关系数据库的角度来看,这很不好,因
问题内容: 这个问题已经在这里有了答案 : 如何从MySQL中的多个表中删除? (7个答案) 2年前关闭。 我有4个表,每个表存储有关用户的不同信息。每个表都有一个带有user_id的字段,用于标识哪个行属于哪个用户。如果要删除用户,这是从多个表中删除该用户信息的最佳方法吗?我的目标是在一个查询中做到这一点。 查询: 问题答案: 您可以使用选项在表上定义外键约束。 然后,从父表中删除记录将从子表中
问题内容: 我有2张桌子,如下所示: serial_table serial_key CHARACTER VARYING(20), PRIMARY KEY(id, serial_key) serial_rate: serial_key CHARACTER VARYING(20), rate NUMERIC, PRIMARY KEY(id, serial_key), FOREIGN KEY (id,