如何避免可能导致数据库中不匹配的间接引用

发布于 2024-10-12 16:18:38 字数 418 浏览 1 评论 0原文

运行 SQL-server 2005 并拥有一个简化版本的数据库模型,如下图所示。

该模型运行得很好,但我的问题是当我想在订阅和地址或端口之间添加引用时。如果我在 Subscriptions.port_id 和 Ports.id 之间创建一个普通的 FK,则可能会喜欢一个端口/地址,该端口/地址引用了另一个客户,而不是订阅所引用的客户。

我想知道是否可以避免这个问题,或者我是否必须在代码中处理该问题并冒着数据不一致的风险?

alt text

注释 地址和端口已预先填充并在创建客户

订阅 之前存在 有些订阅将连接到地址,有些订阅将连接到端口,有些订阅将仅连接到客户。

Running SQL-server 2005 and having a database model, in a simplified version, that looks like the image below.

The model is working pretty well but my problem is when I would like to add a reference between Subscriptions and Addresses or Ports. If I create an ordinary FK between Subscriptions.port_id and Ports.id it will be possible to like to a Port/Addresses that has a reference to another Customer than the one references by the Subscription.

I would like to know if it's possible to avoid this problem or if I'll have to handle the problem in the code and with the risk of inconsistent data?

alt text

Notes
The addresses and ports are pre-populate and exists before the Customers are created

Subscriptions
Some subscription will be connected to an Address, some to Ports and some Subscriptions will only have the connection to the Customer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

热血少△年 2024-10-19 16:18:38

我想知道是否可以避免这个问题,或者我是否必须在代码中处理该问题并冒着数据不一致的风险?

您的模型违反了3NF

不要在订阅中存储 address_idcustomer_id,因为它们是由 port_id 唯一定义的。

相反,仅存储 port_id 并通过联接获取 address_idcustomer_id

I would like to know if it's possible to avoid this problem or if I'll have to handle the problem in the code and with the risk of inconsistent data?

You model violates 3NF.

Don't store address_id and customer_id in subscriptions, since they are uniquely defined by port_id.

Instead, store only port_id and get address_id and customer_id through joins.

手长情犹 2024-10-19 16:18:38

1) Quassnoi 所说的

2) 如果,无论出于何种原因,您确实想要维护表的当前结构:

ALTER TABLE Addresses ADD CONSTRAINT UQ_Addresses_WithCustomers (Id,Customer_ID)

ALTER TABLE Ports ADD CONSTRAINT UQ_Ports_WithAddresses (Id,Address_ID)

这些将超级键添加到这两个表中,以便它们可以通过外键约束引用

ALTER TABLE Subscriptions ADD
    CONSTRAINT FK_Subscription_Addresses (Address_ID,Customer_ID)
    references Addresses (Id,Customer_ID)

ALTER TABLE Subscriptions ADD
    CONSTRAINT FK_Subscription_Ports (Port_ID,Address_ID)
    references Ports (ID, Address_ID)

这些外键现在强制您正在匹配地址表中与address_id 和client_id 都匹配的行。

而且,大概您还没有这个:

ALTER TABLE Subscriptions ADD
    CONSTRAINT CK_Subscription_EnhancedNUllability CHECK
     (Port_ID is null or Address_ID is not null)

因为否则您可能会在订阅表中拥有一个空的address_id和一个非空的port_id,并且这是不可检查的(外键约束将不适用,因为address_id为空)


回复:注释地址和端口是预先填充的,并且在创建客户之前就存在

我会为这些创建单独的表,没有可为空的列,然后引入新表(ClientAddresses、ClientPorts)具有这些地址、端口和客户端表的外键。然后更改上述内容,让订阅引用 ClientAddresses/Ports 表。简而言之,我唯一保留可为空列的表是订阅表,并且上述约束应该足够了。因此,您可以:

CREATE TABLE Addresses (
    AddressID int IDENTITY(1,1) not null,
    Name nchar(10) not null,
    constraint PK_Addresses PRIMARY KEY (AddressID),
    constraint UQ_Address_Names UNIQUE (Name)
)

CREATE TABLE ClientAddresses (
    ClientID int not null,
    AddressID int not null,
    constraint PK_ClientAddresses PRIMARY KEY (AddressID) /*This also prevents the same address being assigned to multiple clients */,
    constraint FK_ClientAddresses_Clients FOREIGN KEY (ClientID) references Clients (ID),
    constraint FK_ClientAddresses_Addresses FOREIGN KEY (AddressID) references Addresses (AddressID),
    constraint UQ_ClientAddresses_WithClients UNIQUE (ClientID,AddressID)
)

UQ_ClientAddresses_WithClients 用作订阅中外键关系的目标。

1) What Quassnoi said

2) If, for whatever reason, you do want to maintain the current structure of the tables:

ALTER TABLE Addresses ADD CONSTRAINT UQ_Addresses_WithCustomers (Id,Customer_ID)

ALTER TABLE Ports ADD CONSTRAINT UQ_Ports_WithAddresses (Id,Address_ID)

These add superkeys to these two tables, so that they can be referenced by foreign key constraints

ALTER TABLE Subscriptions ADD
    CONSTRAINT FK_Subscription_Addresses (Address_ID,Customer_ID)
    references Addresses (Id,Customer_ID)

ALTER TABLE Subscriptions ADD
    CONSTRAINT FK_Subscription_Ports (Port_ID,Address_ID)
    references Ports (ID, Address_ID)

These foreign keys now enforce that you're matching a row in the addresses table that matches both the address_id and the client_id.

And also, presumably you don't have this yet:

ALTER TABLE Subscriptions ADD
    CONSTRAINT CK_Subscription_EnhancedNUllability CHECK
     (Port_ID is null or Address_ID is not null)

Because otherwise you could have a null address_id and a non-null port_id in the subscriptions table, and that isn't checkable (the foreign key constraints wouldn't apply because address_id is null)


Re: Notes The addresses and ports are pre-populated and exist before the Customers are created

I'd create separate tables for these, with no nullable columns, and then introduce new tables (ClientAddresses, ClientPorts) that have foreign keys to these Address, Ports and Client tables. Then change the above to have Subscriptions reference the ClientAddresses/Ports tables instead. In short, the only table I'd leave with nullable columns would be the subscriptions table, and the above constraints should be sufficient there. So you'd have:

CREATE TABLE Addresses (
    AddressID int IDENTITY(1,1) not null,
    Name nchar(10) not null,
    constraint PK_Addresses PRIMARY KEY (AddressID),
    constraint UQ_Address_Names UNIQUE (Name)
)

CREATE TABLE ClientAddresses (
    ClientID int not null,
    AddressID int not null,
    constraint PK_ClientAddresses PRIMARY KEY (AddressID) /*This also prevents the same address being assigned to multiple clients */,
    constraint FK_ClientAddresses_Clients FOREIGN KEY (ClientID) references Clients (ID),
    constraint FK_ClientAddresses_Addresses FOREIGN KEY (AddressID) references Addresses (AddressID),
    constraint UQ_ClientAddresses_WithClients UNIQUE (ClientID,AddressID)
)

with UQ_ClientAddresses_WithClients being used as the target for the foreign key relationship from subscriptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文