另一个外键问题 - #1451 - 无法删除或更新父行:外键约束失败

时间:2013-04-21 01:20:31

标签: mysql foreign-keys foreign-key-relationship

在MySQL中执行此操作时:

UPDATE `client_therapist` SET `therapist_id` = 3 LIMIT 1 ;

我收到以下错误:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails (`test_structure`.`client_group`, CONSTRAINT `client_group_therapist_id` FOREIGN KEY (`therapist_id`) REFERENCES `client_therapist` (`therapist_id`) ON DELETE NO ACTION ON UPDATE NO ACTION) 

我已经搜遍了所有已经阅读过StackOverflow上的几个外键问题...但无济于事。我不认为我现在完全理解外键。

这是我的数据库结构: Database structure diagram showing foreign keys

导致问题的外键位于client_group表中。我的理解是它说“每当添加一行时,therapist_id必须与client_therapist表中的therapist_id匹配。”

只要输入这个就让我意识到问题的一部分是当添加一个client_group时,它可能会被绑定到client_therapist表中的某一行。那么如果我尝试更新那个client_therapist行,那就吓坏了。所以我想我的问题是 - 我该如何解决这个问题?我需要更新client_therapist表中某行的therapist_id,但似乎我不能只要在client_group表中有一行。

以下是我的表格,其中包含一些虚拟信息:

CREATE SCHEMA IF NOT EXISTS `test_structure` DEFAULT CHARACTER SET utf8 ;
USE `test_structure` ;

-- -----------------------------------------------------
-- Table `test_structure`.`user`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `test_structure`.`user` (
  `user_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `email` VARCHAR(80) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL ,
  `password` VARCHAR(40) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL,
  `display_name` VARCHAR(60) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `first_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL ,
  `last_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL ,
  `street_address` VARCHAR(120) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `city` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `state` CHAR(2) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `zip` VARCHAR(10) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `work_phone` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `cell_phone` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `home_phone` VARCHAR(20) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `date_created` TIMESTAMP NULL DEFAULT NULL ,
  `expired` TINYINT(1) NOT NULL DEFAULT '0' ,
  `date_last_login` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ,
  `login_count` INT(10) UNSIGNED NULL DEFAULT '0' ,
  PRIMARY KEY (`user_id`) ,
  UNIQUE INDEX `email` (`email` ASC) )
ENGINE = InnoDB
AUTO_INCREMENT = 0
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci, 
COMMENT = 'Users table.  All Therapists, Clients, Admins and others wil' ;


-- -----------------------------------------------------
-- Table `test_structure`.`client_therapist`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `test_structure`.`client_therapist` (
  `client_therapist_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `client_id` INT(10) UNSIGNED NOT NULL ,
  `therapist_id` INT(10) UNSIGNED NOT NULL ,
  `start_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
  `end_date` TIMESTAMP NULL DEFAULT NULL ,
  `therapist_approval` TINYINT(1) NOT NULL DEFAULT '0' ,
  `date_client_agreed_to_terms` TIMESTAMP NULL DEFAULT NULL ,
  PRIMARY KEY (`client_therapist_id`) ,
  INDEX `client_therapist_client_id` (`client_id` ASC) ,
  INDEX `client_therapist_therapist_id` (`therapist_id` ASC) ,
  CONSTRAINT `client_therapist_client_id`
    FOREIGN KEY (`client_id` )
    REFERENCES `test_structure`.`user` (`user_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `client_therapist_therapist_id`
    FOREIGN KEY (`therapist_id` )
    REFERENCES `test_structure`.`user` (`user_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
AUTO_INCREMENT = 0
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci, 
COMMENT = 'This defines the relationship between a client and therapist' ;



-- -----------------------------------------------------
-- Table `test_structure`.`client_group`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `test_structure`.`client_group` (
  `client_group_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `therapist_id` INT(10) UNSIGNED NOT NULL ,
  `title` VARCHAR(128) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NOT NULL ,
  `description` VARCHAR(255) CHARACTER SET 'utf8' COLLATE 'utf8_unicode_ci' NULL DEFAULT NULL ,
  `date_added` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ,
  PRIMARY KEY (`client_group_id`) ,
  INDEX `client_group_therapist_id` (`therapist_id` ASC) ,
  CONSTRAINT `client_group_therapist_id`
    FOREIGN KEY (`therapist_id` )
    REFERENCES `test_structure`.`client_therapist` (`therapist_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
AUTO_INCREMENT = 0
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;


-- -----------------------------------------------------
-- Table `test_structure`.`client_group_member`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `test_structure`.`client_group_member` (
  `client_group_member_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
  `client_group_id` INT(10) UNSIGNED NOT NULL ,
  `client_id` INT(10) UNSIGNED NOT NULL ,
  PRIMARY KEY (`client_group_member_id`) ,
  INDEX `client_group_id` (`client_group_id` ASC) ,
  INDEX `client_group_member_id` (`client_id` ASC) ,
  CONSTRAINT `client_group_id`
    FOREIGN KEY (`client_group_id` )
    REFERENCES `test_structure`.`client_group` (`client_group_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `client_group_member_id`
    FOREIGN KEY (`client_id` )
    REFERENCES `test_structure`.`client_therapist` (`client_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
AUTO_INCREMENT = 0
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_unicode_ci;


-- -----------------------------------------------------
-- INSERT TEST DATA
-- -----------------------------------------------------
INSERT INTO `test_structure`.`user` (`user_id`, `email`, `password`, `display_name`, `first_name`, `last_name`, `street_address`, `city`, `state`, `zip`, `work_phone`, `cell_phone`, `home_phone`, `date_created`, `expired`, `date_last_login`, `login_count`) VALUES (NULL, 'dr@dr.com', SHA1('12345'), 'Dr. Test', 'Dr.', 'Test', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NOW(), '0', CURRENT_TIMESTAMP, '0');

SET @therapist_id = LAST_INSERT_ID();

INSERT INTO `test_structure`.`user` (`user_id`, `email`, `password`, `display_name`, `first_name`, `last_name`, `street_address`, `city`, `state`, `zip`, `work_phone`, `cell_phone`, `home_phone`, `date_created`, `expired`, `date_last_login`, `login_count`) VALUES (NULL, 'client@client.com', '12345', 'Client', 'Client', 'Client', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NOW(), '0', CURRENT_TIMESTAMP, '0');

SET @client_id = LAST_INSERT_ID();

INSERT INTO `test_structure`.`client_therapist` (`client_therapist_id`, `client_id`, `therapist_id`, `start_date`, `end_date`, `therapist_approval`, `date_client_agreed_to_terms`) VALUES (NULL, @client_id, @therapist_id, CURRENT_TIMESTAMP, NOW(), '0', NOW());

INSERT INTO `test_structure`.`client_group` (`client_group_id`, `therapist_id`, `title`, `description`, `date_added`) VALUES (NULL, @therapist_id, 'Test', NULL, CURRENT_TIMESTAMP);

SET @group_id = LAST_INSERT_ID();

INSERT INTO `test_structure`.`client_group_member` (`client_group_member_id`, `client_group_id`, `client_id`) VALUES (NULL, @group_id, @client_id);

然后运行此代码以查看foreign_key问题:

INSERT INTO `test_structure`.`user` (`user_id`, `email`, `password`, `display_name`, `first_name`, `last_name`, `street_address`, `city`, `state`, `zip`, `work_phone`, `cell_phone`, `home_phone`, `date_created`, `expired`, `date_last_login`, `login_count`) VALUES (NULL, 'newdr@newdr.com', SHA1('12345'), 'New Dr', 'Dr.', 'New', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NOW(), '0', CURRENT_TIMESTAMP, '0');

SET @new_therapist_id = LAST_INSERT_ID();

UPDATE `test_structure`.`client_therapist` SET `therapist_id` = @new_therapist_id LIMIT 1;

非常感谢所有帮助/指导/指导!

更新

我遇到的问题是因为client_group表中的therapist_id绑定到client_therapist表中的therapist_id而不是user表。 therapist_id可以在client_therapist和client_group表中多次存在,但在user表中只能存在一次,所以只要client_group表中的单行仍然引用该therapist_id,我就永远不能更新client_therapist表中的那一列。

我应该做的是将therapist_id绑定到user表而不是client_therapist表,因为最好保留外键引用每个表上的主ID(是真的吗?)。

现在我必须学习如何删除/编辑/更新表格上的外键......:)

2 个答案:

答案 0 :(得分:2)

您需要使用ON UPDATE CASCADE选项声明的外键。

以下是如何在表上删除和添加外键的示例:

ALTER TABLE client_group drop FOREIGN KEY `client_group_therapist_id`, 
  ADD FOREIGN KEY `client_group_therapist_id` (`therapist_id`) 
  REFERENCES `client_therapist` (`therapist_id`) ON DELETE NO ACTION ON UPDATE CASCADE;

然后,如果您更改client_therapist.therapist_id中的值,它会自动更新client_group.therapist_id中的值。

此更改将是同步和原子的 - 也就是说,没有其他同时运行的查询将能够在一个表中看到更改的数据而在另一个表中没有更改。

答案 1 :(得分:0)

外键不正确,因为它引用了另一个表中的非唯一列。

我应该做的是将therapist_id绑定到user表而不是client_therapist表,因为最好保留外键引用每个表上的主ID。

ALTER TABLE client_group drop FOREIGN KEY `client_group_therapist_id`, 
ADD FOREIGN KEY `client_group_therapist_id` (`therapist_id`) 
REFERENCES `user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION;