如何建立约束,其中一列(不是主键)必须与另一个表的列具有相同的值。我不太清楚怎么说它所以这是一个例子:
例:
我有三个表,Employee
,Director
,Division
和Department
表的结构如下:
员工
总
系
司
员工和董事都有部门,每个部门都有一个部门,但他们的部门必须相同。有没有办法强制执行此操作? (希望不必使用触发器)
答案 0 :(得分:3)
创建具有适当GRANTS的存储过程,并且不允许用户直接INSERT到表中。使用存储过程作为数据库的接口,并在插入之前检查其中所需的条件。
答案 1 :(得分:1)
创建外键没有限制 - 没有什么可以阻止您在这些表上定义外键约束:
...将它们与DEPARTMENT表相关联。虽然坦率地说,我认为不需要DIRECTOR表 - 它应该是EMPLOYEE表中的布尔指示符,或者可能是EMPLOYEE_TYPE_CODE,它有自己的外键约束来区分员工和董事。
外键的存在也不会阻止您在同一列上放置第二个(或第三个等)约束。考虑TABLE_C.column具有TABLE_A.col和TABLE_B.col的外键约束的情况 - 这在数据库中是完全可以接受的,但这意味着只有TABLE_A.col和TABLE_B.col中存在的值才能存在于TABLE_C.column。 IE:
col
----
a
b
c
col
----
c
基于此示例数据,TABLE_C.column只允许“c”作为值存在于列中,如果有人向TABLE_C.column添加了两个外键约束,引用TABLE_A.col和TABLE_B.col。
答案 2 :(得分:1)
首先,您的示例表做得太多了。有一个设计原则规定单个表应该模拟实体或实体之间的关系,但不能同时建模。部门,董事和员工之间的关系(我假设董事不是员工;我现在也忽略了部门)。
其次,一个表可以有多个密钥,称为候选密钥。此外,您可以通过向键添加非唯一列来创建UNIQUE
约束。例如,员工的姓名不能成为一个好的密钥,因此有一个员工ID的原因(我不认为对于部门来说也是如此,即部门名称本身就是一个足够好的密钥)。如果employee_ID
是唯一的,那么(employee_name, employee_ID)
也将是唯一的。
第三,任何UNIQUE
约束都可以引用一个表,它不必是表的'主'键(这部分解释了为什么'主键'有点无意义)。< / p>
上述优点是可以使用FOREIGN KEY
和行级CHECK
约束来建模所需的约束。 SQL优化器和程序员更喜欢声明性解决方案到过程代码(触发器,存储过程等)。这个vanilla SQL DDL将移植到大多数SQL产品。
因此,部门名称可以分别与导演密钥和员工密钥结合使用,这些复合密钥可以在简单的两层组织结构图表中引用:因为员工部门及其主管部门都将出现在在同一个表中,可以使用简单的行级CHECK
约束来测试它们是否相同,例如
实体表:
CREATE TABLE Departments
(
department_name VARCHAR(30) NOT NULL UNIQUE
);
CREATE TABLE Employees
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_name VARCHAR(100) NOT NULL
);
CREATE TABLE Directors
(
director_ID INTEGER NOT NULL UNIQUE,
director_name VARCHAR(100) NOT NULL
);
关系表:
CREATE TABLE EmployeeDepartments
(
employee_ID INTEGER NOT NULL UNIQUE
REFERENCES Employees (employee_ID),
employee_department_name VARCHAR(30) NOT NULL
REFERENCES Departments (department_name),
UNIQUE (employee_department_name, employee_ID)
);
CREATE TABLE DirectorDepartments
(
director_ID INTEGER NOT NULL UNIQUE
REFERENCES Directors (director_ID),
director_department_name VARCHAR(30) NOT NULL
REFERENCES Departments (department_name),
UNIQUE (director_department_name, director_ID)
);
CREATE TABLE OrgChart
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_department_name VARCHAR(30) NOT NULL,
FOREIGN KEY (employee_department_name, employee_ID)
REFERENCES EmployeeDepartments
(employee_department_name, employee_ID),
director_ID INTEGER NOT NULL,
director_department_name VARCHAR(30) NOT NULL,
FOREIGN KEY (director_department_name, director_ID)
REFERENCES DirectorDepartments
(director_department_name, director_ID),
CHECK (employee_department_name = director_department_name)
);
现在一个稍微有趣的场景是,当一名董事被分配一个部门而不是一个特定的部门时,你必须测试该员工的部门与她的董事在同一部门:
实体表:
CREATE TABLE Divisions
(
division_name VARCHAR(20) NOT NULL UNIQUE
);
CREATE TABLE Departments
(
department_name VARCHAR(30) NOT NULL UNIQUE,
division_name VARCHAR(20) NOT NULL
REFERENCES Divisions (division_name),
UNIQUE (division_name, department_name)
);
CREATE TABLE Employees
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_name VARCHAR(100) NOT NULL
);
CREATE TABLE Directors
(
director_ID INTEGER NOT NULL UNIQUE,
director_name VARCHAR(100) NOT NULL
);
关系表:
CREATE TABLE EmployeeDepartments
(
employee_ID INTEGER NOT NULL UNIQUE
REFERENCES Employees (employee_ID),
employee_department_name VARCHAR(30) NOT NULL
REFERENCES Departments (department_name),
UNIQUE (employee_department_name, employee_ID)
);
CREATE TABLE DirectorDivisions
(
director_ID INTEGER NOT NULL UNIQUE
REFERENCES directors (director_ID),
director_division_name VARCHAR(20) NOT NULL
REFERENCES divisions (division_name),
UNIQUE (director_division_name, director_ID)
);
CREATE TABLE OrgChart
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_department_name VARCHAR(30) NOT NULL,
FOREIGN KEY (employee_department_name, employee_ID)
REFERENCES EmployeeDepartments
(employee_department_name, employee_ID),
employee_division_name VARCHAR(20) NOT NULL
REFERENCES divisions (division_name),
FOREIGN KEY (employee_division_name, employee_department_name)
REFERENCES Departments (division_name, department_name),
director_ID INTEGER NOT NULL,
director_division_name VARCHAR(20) NOT NULL,
FOREIGN KEY (director_division_name, director_ID)
REFERENCES DirectorDivisions
(director_division_name, director_ID),
CHECK (employee_division_name = director_division_name)
);