mysql主外键删除顺序,具有外键约束的删除顺序,

I have a schema with three tables and foreign key 'On Delete' constraints as below:

| -> FK (cascade) -> |

Organisation | | Users

| - FK (cascade) Categories -> FK(restrict) -> |

If I delete an organisation I want to delete the users and the categories related to it, but I can't allow a category to be deleted if a user refers to it except in the case where the whole organisation is being deleted.

At present if I delete an organisation the category deletion fails if there's a user referring to it. This seems to indicate that MySQl is processing the foreign key constraints on the Categories table before the Users table.

This wouldn't be a problem if the Users in the user table were cleared before the Categories.

Is there a way to tell MySQl what order to process these FK constraints so that the tables get cleared in a specified order?

Note: I could add some code to explicitly clear the user table first, but that's fiddly within the design of the code so I don't want to go there yet.

Note also that the required security limits what I can do with the schema on-the-fly, so changing the FK constraints or disabling checking of them is not really an option. I can change the security to make a one-time change. I don't want to loosen security permanently unless there's no other way. Writing extra code as above is preferred

Here are the Create statements for the tables, edited to remove unrelated fields.

CREATE TABLE `organisation` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`orgGUID` varchar(36) NOT NULL,

`archivedFlag` tinyint(3) unsigned NOT NULL DEFAULT '0',

`orgName` varchar(45) NOT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `id_UNIQUE` (`id`),

UNIQUE KEY `org_guid_UNIQUE` (`orgGUID`)

) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8;

CREATE TABLE `user` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`userGUID` varchar(36) NOT NULL,

`name` varchar(45) NOT NULL,

`orgGUID` varchar(36) NOT NULL,

`userType` smallint(6) DEFAULT NULL,

`PwHash` varchar(255) DEFAULT NULL,

`ethnicityGUID` varchar(36) DEFAULT NULL ,

`genderGUID` varchar(36) DEFAULT NULL ,

`yearGroupGUID` varchar(36) DEFAULT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `id_UNIQUE` (`id`),

UNIQUE KEY `userGUID_UNIQUE` (`userGUID`),

KEY `fk_user_org_idx` (`orgGUID`),

KEY `fk_ethnicity_category_idx` (`ethnicityGUID`),

KEY `fk_gender_category_idx` (`genderGUID`),

CONSTRAINT `fk_ethnicity_category` FOREIGN KEY (`ethnicityGUID`) REFERENCES `categories` (`id`) ON UPDATE NO ACTION,

CONSTRAINT `fk_gender_category` FOREIGN KEY (`genderGUID`) REFERENCES `categories` (`id`) ON UPDATE NO ACTION,

CONSTRAINT `fk_user_org` FOREIGN KEY (`orgGUID`) REFERENCES `organisation` (`orgGUID`) ON DELETE CASCADE ON UPDATE NO ACTION

) ENGINE=InnoDB AUTO_INCREMENT=162 DEFAULT CHARSET=utf8;

CREATE TABLE `categories` (

`id` varchar(36) NOT NULL,

`orgGUID` varchar(36) NOT NULL,

`categoryType` varchar(20) NOT NULL,

`category` varchar(45) NOT NULL,

`priority` int(11) NOT NULL,

`analysisCode` varchar(20) NOT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `id_UNIQUE` (`id`),

KEY `fk_category_org_idx` (`orgGUID`),

CONSTRAINT `fk_category_org` FOREIGN KEY (`orgGUID`) REFERENCES `organisation` (`orgGUID`) ON DELETE CASCADE ON UPDATE NO ACTION

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

解决方案

Officially, you have no control over the order of the cascaded operations. You may be able to abuse some undocumented behaviour however:

for MySQL 5.5, the foreign keys are executed in the order they got created, so dropping and recreating the fk_category_org-constraint should work

for MySQL 5.6+, the foreign keys are executed in the lexical order of their names, so renaming fk_category_org to e.g. fk_z_category_org should work

This is undocumented and can change anytime (and might be influenced by other factors).

That being said, the proper way to do this (and anything else too complicated for on cascade) would be to add a before delete-trigger on your organisation-table that "manually" deletes the users first and then the categories afterwards. before delete-triggers are executed before on cascade (so you can decide if you want to keep those or not, although it would probably be misleading).

It is not entirely clear if that is your intented behaviour, but currently, a user can have a category that belongs to organization 1 while he is assigned to organization 2. Deleting organization 1 would then still fail. It looks a bit as if that is what you want to prevent by your design, but if you want the deletion to work in this case too, you need to use the trigger to be able to incorporate that (or manually delete it in your application), cascading will not work unless you also cascade in the category table.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值