Mar*_*las 9 sql sql-server oop database-design
假设我有一张表代表超级班的学生.然后我有N个表格代表该对象的子类(运动员,音乐家等).我如何表达一个约束,以便学生必须在一个(不多于,不少于)子类中建模?
有关评论的澄清:
A)以真正的面向对象的方式,超类可以自己存在,不需要在任何子类中建模.
B)在现实生活中,任何对象或学生都可以有多个角色.
C)我试图说明的特定场景要求每个对象只在一个子类中实现.将超类视为抽象实现,或者只考虑其他不同的对象类/实例中的共性.
感谢大家的投入,特别是比尔.
这里有几种可能性。一个是CHECK
每个表中的一个,它student_id
不会出现在任何其他姐妹子类型表中。这可能很昂贵,并且每次需要新的子类型时,都需要修改所有现有表中的约束。
CREATE TABLE athletes (
student_id INT NOT NULL PRIMARY KEY,
FOREIGN KEY (student_id) REFERENCES students(student_id),
CHECK (student_id NOT IN (SELECT student_id FROM musicians
UNION SELECT student_id FROM slackers
UNION ...))
);
Run Code Online (Sandbox Code Playgroud)
编辑: @JackPDouglas 正确指出 Microsoft SQL Server 不支持上述形式的 CHECK 约束。事实上,根据 SQL-99 标准引用另一个表也是无效的(请参阅http://kb.askmonty.org/v/constraint_type-check-constraint)。
SQL-99 定义了多表约束的元数据对象。这称为ASSERTION,但是我不知道有任何 RDBMS 实现了断言。
可能更好的方法是使表中的主键students
成为复合主键,第二列表示子类型。然后将每个子表中的该列限制为与该表表示的子类型相对应的单个值。 编辑:无需将 PK 作为子表中的复合键。
CREATE TABLE athletes (
student_id INT NOT NULL PRIMARY KEY,
student_type CHAR(4) NOT NULL CHECK (student_type = 'ATHL'),
FOREIGN KEY (student_id, student_type) REFERENCES students(student_id, student_type)
);
Run Code Online (Sandbox Code Playgroud)
当然student_type
也可以很容易地是一个整数,我只是将其显示为一个字符以用于说明目的。
如果您不支持CHECK
约束(例如MySQL),那么您可以在触发器中执行类似的操作。
我阅读了您的后续内容,内容涉及确保超类表中的每一行都存在于某个子类表中。我认为没有一种实用的方法可以使用 SQL 元数据和约束来做到这一点。我建议满足此要求的唯一选择是使用Single-Table Inheritance。否则,您需要依赖应用程序代码来强制执行它。
编辑: JackPDouglas 还建议使用基于类表继承的设计。请参阅他的示例或我的类似技术示例(此处或此处或此处)。