题
我正在考虑设计类似于以下内容的数据库模式:
Person (
PersonID int primary key,
PrimaryAddressID int not null,
...
)
Address (
AddressID int primary key,
PersonID int not null,
...
)
Person.PrimaryAddressID和Address.PersonID将是相应表的外键。
显而易见的问题是,无法在任何一个表中插入任何内容。有没有办法设计一个工作模式来强制每个具有主要地址的人员?
解决方案
<!>“我相信这是不可能的。在知道人员的ID之前,您无法创建地址记录,并且在知道PrimaryAddressId字段的AddressId之前无法插入人员记录。<!> quot;
从表面上看,这种主张似乎很有吸引力。但是,这很有道理。
这是一个非常常见的问题,SQL DBMS供应商已经尝试攻击了几十年了。
关键是所有约束检查必须是<!> quot; deferred <!> quot;直到两个插入完成。这可以通过不同的形式实现。数据库事务可以提供类似<!>“SET延迟约束检查ON <!>”的操作的可能性,并且你已经完成了(如果不是因为在这个特定的例子中,你可能不得不你的设计非常困难,以便能够定义两个FK约束,因为其中一个只是在SQL意义上不是'真正的'FK!)。
此处所述的基于触发器的解决方案实现了基本相同的效果,但这些解决方案暴露于应用程序强制完整性所存在的所有维护问题。
在他们的作品中,Chris Date <!> amp; Hugh Darwen描述了什么是这个问题的真正解决方案:多重任务。也就是说,基本上,可以组成几个不同的更新语句并让DBMS对其进行操作,就好像这是一个单一的语句。这个概念的实现确实存在,但你找不到任何谈论SQL的东西。
其他提示
我们在地址表中标记主要地址,然后使用仅强制执行每人记录的触发器(但必须有一条记录)。如果更改主地址,它将更新旧的主地址以及新的主地址。如果删除主地址并且存在其他地址,则会将其中一个(基于一系列规则)提升为主地址。如果插入了地址并且插入了第一个地址,则会自动将该地址标记为主地址。
这是多对多关系的完美范例。要解决这个问题,您应该拥有中间PERSON_ADDRESS表。换句话说;
PERSON table
person_id (PK)
ADDRESS table
address_id (PK)
PERSON_ADDRESS
person_id (FK) <= PERSON
address_id (FK) <= ADDRESS
is_primary (BOOLEAN - Y/N)
通过这种方式,您可以为PERSON分配多个地址,并在多个PERSON中重复使用ADDRESS记录(适用于家庭成员,同一公司的员工等)。使用PERSON_ADDRESS表中的is_primary字段,您可以识别该person_addrees组合是否是某人的主要地址。
第二个FK(PersonId from Address to Person)限制性太强,恕我直言。你是建议一个地址只能有一个人吗?
从您的设计来看,地址似乎只适用于一个人,因此只需使用PersonID作为地址表的键,然后删除AddressID键字段。
我知道我可能会被钉在十字架上或者其他什么,但是这里......
我已经为我的<!>做了这样的事情;特别是非常独特且非标准的<!>业务需求(=(即使我说话,上帝我开始听起来像SQL DDL)。
这是一个例子:
CREATE TABLE IF NOT EXISTS PERSON(
ID INT,
CONSTRAINT PRIMARY KEY (ID),
ADDRESS_ID INT NOT NULL DEFAULT 1,
DESCRIPTION VARCHAR(255),
CONSTRAINT PERSON_UQ UNIQUE KEY (ADDRESS_ID, ...));
INSERT INTO PERSON(ID, DESCRIPTION)
VALUES (1, 'GOVERNMENT');
CREATE TABLE IF NOT EXISTS ADDRESS(
ID INT,
CONSTRAINT PRIMARY KEY (ID),
PERSON_ID INT NOT NULL DEFAULT 1,
DESCRIPTION VARCHAR(255),
CONSTRAINT ADDRESS_UQ UNIQUE KEY (PERSON_ID, ...),
CONSTRAINT ADDRESS_PERSON_FK FOREIGN KEY (PERSON_ID) REFERENCES PERSON(ID));
INSERT INTO ADDRESS(ID, DESCRIPTION)
VALUES (1, 'ABANDONED HOUSE AT THIS ADDRESS');
ALTER TABLE PERSON ADD CONSTRAINT PERSON_ADDRESS_FK FOREIGN KEY (ADDRESS_ID) REFERENCES ADDRESS(ID);
<!> LT; ...生活还在继续......无论你是否为这个人提供和解决,反之亦然<!> gt;
我定义了一个表,然后另一个表引用第一个表,然后更改第一个表以反映对第二个表的引用(在第一个表创建时不存在)。它不适用于特定的数据库;如果我需要它我只是尝试它,如果它工作,然后我使用它,如果没有那么我尽量避免在设计中有这种需要(我不能总是控制它,有时设计是按原样交给我) 。如果你有一个没有人的地址,那么它属于<!> quot; government <!> quot;人。如果你有一个<!>“无家可归的人<!>”;然后它得到<!>“废弃的房子<!>”;地址。我运行一个流程来确定哪些房屋没有用户