2

在我必须为 MS Access 设计的数据库中,我有一个名为“Measurements”的表,它存储某些测量参数(测量值、标准偏差等) - 每行都有一个整数 ID 作为其主键。

然后其他表使用外键关系链接到该测量表。一些表包含两个不同的“measurementID”字段,它们都链接到这个测量表。但是,每次测量都应该只与这些字段之一相关联。

如何对多个表中的多个字段强制执行唯一性约束?有办法吗?

4

5 回答 5

3

Microsoft ACE/Jet 引擎不支持触发器,这是您通常实现此类功能的方式。

编辑:正如@onedaywhen 所指出的,JET 4.0 及以后的版本确实支持检查约束,但在两列之间实现异或类型约束并不简单。

如果您使用的是访问表单,您可以实现表单的更新前事件并检查您的约束条件。

于 2009-04-09T00:22:33.450 回答
3

这样的约束确实可以在 ACE/JET 中使用CHECK约束来实现。

说他们通常会为这种事情使用触发器的人并没有意识到CHECKACE/Jet 和 SQL Server 中的约束之间的区别:在 SQL Server 中它们不能包含子查询,这意味着它们不能引用其他行中的值在同一个表或其他表中,而在 ACE/Jet 中可以。

在一个理想的(但尚未 AFAIK 不存在的)SQL-92 产品中,所描述的唯一性将使用ASSETION, 在模式级别实现。因为 CHECK 约束是表级的,并且仅在定义它们的表是UPDATEd 或INSERTed 时才检查,因此您需要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 KEYs 和行级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
)
;
于 2009-04-09T08:28:07.683 回答
0

Mitch 对于 Access 中的可能性是正确的。但是,假设您在某处拥有 BL,这将逐渐成为合法的业务规则。那是我最有可能做的。

于 2009-04-09T00:37:21.340 回答
0

鉴于您正在设计此数据库。您确定您的表结构遵循标准规范化规则。

根据您正在查看的 A.row 字段,表 A 中的一行能够引用表 Measurements 中的两行,这听起来是一种不寻常的结构。我觉得表 Measurments 中的数据确实需要拆分为两个或多个表。

于 2009-04-09T01:33:44.870 回答
0

我自己对触发器和检查约束保持警惕,主要是因为我开发的大多数应用程序都没有它们(Access/Jet 和 MySQL/MyISAM)。我同意 BobClegg 的观点,这听起来像是一种超类型/子类型的情况。在这种情况下,您将使用一个连接表,该表在外键上有一个唯一索引,并且有一列指示它是哪种类型的度量。FK 上的唯一索引将阻止添加第二种类型。这也意味着您的主记录中不会有空字段。当然,一个空的数字字段不是存储问题,但是两个独占的字段在我看来总是设计错误。

于 2009-04-09T22:07:19.467 回答