我正在考虑设计类似于以下内容的数据库模式:
Person (
PersonID int primary key,
PrimaryAddressID int not null,
...
)
Address (
AddressID int primary key,
PersonID int not null,
...
)
Person.PrimaryAddressID和Address.PersonID将是相应表的外键。
显而易见的问题是,无法在任何一个表中插入任何内容。有没有办法设计一个工作模式来强制每个具有主要地址的人员?
答案 0 :(得分:11)
“我认为这是不可能的。在知道人员的身份证之前,您无法创建地址记录,并且在知道PrimaryAddressId字段的AddressId之前无法插入人员记录。”
从表面上看,这种主张似乎很有吸引力。但是,这很有道理。
这是一个非常常见的问题,SQL DBMS供应商已经尝试攻击了几十年了。
关键是所有约束检查必须“延迟”,直到两个插入完成。这可以通过不同的形式实现。数据库事务可以提供类似“设置延迟约束检查”的操作的可能性,并且您已完成(如果不是因为在这个特定示例中,您可能必须非常努力地将您的设计搞乱能够只定义两个FK约束,因为其中一个只是在SQL意义上不是'真正的'FK!)。
此处所述的基于触发器的解决方案实现了基本相同的效果,但这些解决方案暴露于应用程序强制完整性所存在的所有维护问题。
在他们的作品中,Chris Date& Hugh Darwen描述了什么是这个问题的真正解决方案:多重任务。也就是说,基本上,可以组成几个不同的更新语句,并让DBMS对其进行操作,就好像这是一个单一的语句。这个概念的实现确实存在,但你找不到任何谈论SQL的东西。
答案 1 :(得分:2)
我们在地址表中标记主要地址,然后使用仅强制执行每人记录的触发器(但必须有一条记录)。如果更改主地址,它将更新旧的主地址以及新的主地址。如果删除主地址并且存在其他地址,则会将其中一个(基于一系列规则)提升为主地址。如果插入了地址并且插入了第一个地址,则会自动将该地址标记为主地址。
答案 2 :(得分:2)
这是多对多关系的完美范例。要解决这个问题,您应该拥有中间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组合是否是某人的主要地址。
答案 3 :(得分:0)
第二个FK(PersonId from Address to Person)限制性太强,恕我直言。你是建议一个地址只能有一个人吗?
答案 4 :(得分:0)
从您的设计来看,地址似乎只适用于一个人,因此只需使用PersonID作为地址表的键,然后删除AddressID键字段。
答案 5 :(得分:-1)
我知道我可能会被钉在十字架上或者其他什么,但是这里......
我这样做是因为我的“特别非常独特和非标准”的业务需求(=(即使我说话,上帝我开始听起来像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;
我定义了一个表,然后另一个表引用第一个表,然后更改第一个表以反映对第二个表的引用(在第一个表创建时不存在)。它不适用于特定的数据库;如果我需要它我只是尝试它,如果它工作,然后我使用它,如果没有那么我尽量避免在设计中有这种需要(我不能总是控制它,有时设计是按原样交给我) 。如果你有一个没有人的地址,那么它属于“政府”人。如果你有一个“无家可归者”,那么它就会获得“废弃的房子”地址。我运行一个流程来确定哪些房屋没有用户