在我必须为 MS Access 设计的数据库中,我有一个名为“Measurements”的表,它存储某些测量参数(测量值、标准偏差等) - 每行都有一个整数 ID 作为其主键。
然后其他表使用外键关系链接到该测量表。一些表包含两个不同的“measurementID”字段,它们都链接到这个测量表。但是,每次测量都应该只与这些字段之一相关联。
如何对多个表中的多个字段强制执行唯一性约束?有办法吗?
在我必须为 MS Access 设计的数据库中,我有一个名为“Measurements”的表,它存储某些测量参数(测量值、标准偏差等) - 每行都有一个整数 ID 作为其主键。
然后其他表使用外键关系链接到该测量表。一些表包含两个不同的“measurementID”字段,它们都链接到这个测量表。但是,每次测量都应该只与这些字段之一相关联。
如何对多个表中的多个字段强制执行唯一性约束?有办法吗?
Microsoft ACE/Jet 引擎不支持触发器,这是您通常实现此类功能的方式。
编辑:正如@onedaywhen 所指出的,JET 4.0 及以后的版本确实支持检查约束,但在两列之间实现异或类型约束并不简单。
如果您使用的是访问表单,您可以实现表单的更新前事件并检查您的约束条件。
这样的约束确实可以在 ACE/JET 中使用CHECK
约束来实现。
说他们通常会为这种事情使用触发器的人并没有意识到CHECK
ACE/Jet 和 SQL Server 中的约束之间的区别:在 SQL Server 中它们不能包含子查询,这意味着它们不能引用其他行中的值在同一个表或其他表中,而在 ACE/Jet 中可以。
在一个理想的(但尚未 AFAIK 不存在的)SQL-92 产品中,所描述的唯一性将使用ASSETION
, 在模式级别实现。因为 CHECK 约束是表级的,并且仅在定义它们的表是UPDATE
d 或INSERT
ed 时才检查,因此您需要CHECK
对所有引用表施加适当的约束(同样适用于 SQL Server 触发器)。这是一个简单的例子:
CREATE TABLE Parent
(
parent_ID INTEGER NOT NULL IDENTITY UNIQUE,
data_col INTEGER NOT NULL
)
;
CREATE TABLE Child1
(
parent_ID INTEGER NOT NULL
REFERENCES parent (parent_ID),
data_col INTEGER NOT NULL
)
;
CREATE TABLE Child2
(
parent_ID INTEGER NOT NULL
REFERENCES parent (parent_ID),
data_col INTEGER NOT NULL
)
;
ALTER TABLE Child1 ADD
CONSTRAINT child1__no_dups_in_child2
CHECK (NOT EXISTS (
SELECT *
FROM Child1 AS C1
INNER JOIN Child2 AS C2
ON C1.parent_ID = C2.parent_ID
))
;
ALTER TABLE Child2 ADD
CONSTRAINT child2__no_dups_in_child1
CHECK (NOT EXISTS (
SELECT *
FROM Child1 AS C1
INNER JOIN Child2 AS C2
ON C1.parent_ID = C2.parent_ID
))
;
但是,我想知道您是否有子类(即可以键入由 ID 表示的每个实体),在这种情况下,您应该能够使用FOREIGN KEY
s 和行级CHECK
约束(如果您对 MS 更满意,则可以使用验证规则访问接口而不是CHECK
约束所需的 SQL DLL)。该逻辑将比表级约束更容易实现,只需注意引用操作CHECK
中的循环即可。CASCADE
这是另一个简单的例子:
CREATE TABLE Parent
(
parent_ID INTEGER NOT NULL IDENTITY,
child_type VARCHAR(4) NOT NULL,
CONSTRAINT child_type__values
CHECK (child_type IN ('Boy', 'Girl')),
UNIQUE (child_type, parent_ID)
)
;
CREATE TABLE Girls
(
parent_ID INTEGER NOT NULL,
child_type VARCHAR(4) DEFAULT 'girl' NOT NULL,
CONSTRAINT girl_child_type__must_be_girl
CHECK (child_type = 'girl'),
FOREIGN KEY (child_type, parent_ID)
REFERENCES Parent (child_type, parent_ID),
data_col INTEGER NOT NULL
)
;
CREATE TABLE Boys
(
parent_ID INTEGER NOT NULL,
child_type VARCHAR(4) DEFAULT 'boy' NOT NULL,
CONSTRAINT boy_child_type__must_be_boy
CHECK (child_type = 'boy'),
FOREIGN KEY (child_type, parent_ID)
REFERENCES Parent (child_type, parent_ID),
data_col INTEGER NOT NULL
)
;
Mitch 对于 Access 中的可能性是正确的。但是,假设您在某处拥有 BL,这将逐渐成为合法的业务规则。那是我最有可能做的。
鉴于您正在设计此数据库。您确定您的表结构遵循标准规范化规则。
根据您正在查看的 A.row 字段,表 A 中的一行能够引用表 Measurements 中的两行,这听起来是一种不寻常的结构。我觉得表 Measurments 中的数据确实需要拆分为两个或多个表。
我自己对触发器和检查约束保持警惕,主要是因为我开发的大多数应用程序都没有它们(Access/Jet 和 MySQL/MyISAM)。我同意 BobClegg 的观点,这听起来像是一种超类型/子类型的情况。在这种情况下,您将使用一个连接表,该表在外键上有一个唯一索引,并且有一列指示它是哪种类型的度量。FK 上的唯一索引将阻止添加第二种类型。这也意味着您的主记录中不会有空字段。当然,一个空的数字字段不是存储问题,但是两个独占的字段在我看来总是设计错误。