我有一个用户表,他可以是教师或校长。我认为这种脱节专业化在ER中是合适的。我使用MySQL dbms,在创建表后,我在User表中创建了一个用户(例如UserId = 31)。但问题是,当我使用UserId = 31将新记录插入教师表并在校长表中插入相同的UserId时,它不会给出任何错误。我认为这被认为违反了不相关的财产。
我有一个具有此属性的用户表
用户(UserId,用户名,密码,性别,姓名,地址,教育,大学,手机)。
和像这样的映射后的教师表
老师(用户ID,疗程)。
和校长表。 校长(用户ID,Years_Of_Service)。
当我创建了老师和校长表时,我创建了它们而没有主键,然后我在每个表中添加了UserId属性的索引,并在User表中引用了UserId。
我的问题:如何使用MySQL实现表格的不相交?
提前致谢
答案 0 :(得分:0)
这样做的一种方法是为每个表添加类型指示符,以及包含类型指示符的FK约束。
我只是要显示超类型以及一个子类型表。
CREATE TABLE `User` (
`UserID` bigint(21) NOT NULL,
`UserType` enum('H', 'T') NOT NULL,
...
PRIMARY KEY (`UserID`),
UNIQUE KEY (`UserID`,`UserType`)
) ENGINE=InnoDB;
CREATE TABLE `Teacher` (
`UserID` bigint(21) NOT NULL,
`UserType` enum('H', 'T') NOT NULL,
...
PRIMARY KEY (`UserID`),
FOREIGN KEY (`UserID`, `UserType`) REFERENCES `User` (`UserID`, `UserType`) ON UPDATE CASCADE
) ENGINE=InnoDB;
请注意,必须在超类型和子类型表中以相同的方式定义UserType
列才能创建FK约束。我在User表中添加了一个唯一键,以支持子类型中的复合FK约束。要限制每个子类型表中的类型指示器,我们然后创建触发器:
DELIMITER ;;
CREATE TRIGGER check_teacher_insert BEFORE INSERT ON Teacher
FOR EACH ROW
BEGIN
IF new.UserType != 'T' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid UserType in Teacher';
END IF;
END;
;;
CREATE TRIGGER check_teacher_update BEFORE UPDATE ON Teacher
FOR EACH ROW
BEGIN
IF new.UserType != 'T' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid UserType in Teacher';
END IF;
END;
;;
DELIMITER ;
另一种方法是省略类型指标,只使用触发器:
DELIMITER ;;
CREATE TRIGGER check_teacher_insert BEFORE INSERT ON Teacher
FOR EACH ROW
BEGIN
IF EXISTS (
SELECT 1
FROM Headmaster
WHERE UserID = new.UserID
) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid UserID in Teacher - already exists in HeadMaster';
END IF;
END;
;;
CREATE TRIGGER check_teacher_update BEFORE UPDATE ON Teacher
FOR EACH ROW
BEGIN
IF EXISTS (
SELECT 1
FROM Headmaster
WHERE UserID = new.UserID
) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid UserID in Teacher - already exists in HeadMaster';
END IF;
END;
;;
DELIMITER ;