我有一个带有主键的表(让我们称之为“人”),以及另一个引用它的表(我们称之为“成绩”,如学生成绩)。
表“等级”具有字段“grade.personid”,它是“person.personid”的外键。让我们说“人”也有字段“person.type”(varchar与“学生”或“老师”的可能值一样简单),只有学生才有成绩。
如何使数据库拒绝任何将非学生(即教师)的“personid”放入“grade.personid”字段的插入/更新。
我目前正在使用Sql Server 2008,但也会对其他平台的答案感兴趣。
[ grade ]
[ person ] [--------]
[--------] [gradeid ]
[personid] <-FK- [personid]
[type ] [data ]
[name ]
P.S。我知道模式绑定视图的约束,但并不真正喜欢它们,因为只要有人修改了他们所依赖的表,它就会中断。
答案 0 :(得分:4)
试试这个:
[ grade ]
[ person ] [--------]
[--------] [gradeid ]
[personid] <-FK- [personid]
[type ] <-FK- [type ]
[name ] [data ]
在personid +类型上放置一个FK,并在grade.type上添加一个检查约束,仅允许学生类型。
答案 1 :(得分:2)
如果是SQL Server,可以通过定义INSTEAD OF
触发器来实现所需的逻辑。例如,对于Mysql服务器,您需要定义BEFORE
触发器。
<强>更新即可。触发器示例(SQL服务器)
CREATE TRIGGER ON [grades] INSTEAD INSERT
AS
BEGIN
IF NOT EXISTS(
SELECT 1 FROM [person] WHERE personid = inserted.person_id AND person.type = 'student'
)
BEGIN
RAISERROR ('Invalid person type', 10, 1);
END;
INSERT INTO [grades] SELECT field1, field2, ... FROM inserted;
END
GO
对于mysql,它应该是CREATE TRIGGER ... BEFORE INSERT
。此外,mysql没有RAISEERROR
的模拟,因此您需要生成错误以防止插入。通常,我使用INSERT INTO not_existing_table(id) VALUES(1,2)
来获取触发器主体中的运行时错误。
答案 2 :(得分:0)
记录中,这是一个对我有用的匿名版本:
CREATE TRIGGER trigRestrictGradeToStudents
ON dbo.grade
FOR INSERT, UPDATE
AS
IF NOT EXISTS (
SELECT person.personid
FROM person
INNER JOIN inserted ON person.personid = inserted.personid
WHERE (type = 'student')
)
BEGIN
ROLLBACK TRANSACTION --prevent the insert/update from proceeding
RAISERROR ('Only students may have grade records', 11, 1)
END
严重性设置为11,使其显示在“事务在触发器中结束之前的错误消息中。批处理已中止。”
另见RAISERROR(原文如此)