首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >确保SQL Server中的两个列值相关

确保SQL Server中的两个列值相关
EN

Stack Overflow用户
提问于 2019-05-30 01:07:06
回答 2查看 0关注 0票数 0

我正在使用Microsoft SQL Server 2017,并对如何约束特定关系感到好奇。我在表达方面遇到了一些麻烦,所以我宁愿通过一个例子来分享。

请考虑以下假设数据库。

代码语言:javascript
复制
Customers
+---------------+
|  Id  |  Name  |
+---------------+
|  1   |  Sam   |
|  2   |  Jane  |
+---------------+
代码语言:javascript
复制
Addresses
+----------------------------------------+
|  Id  |  CustomerId  |  Address         |
+----------------------------------------+
|  1   |  1           |  105 Easy St     |
|  2   |  1           |  9 Gale Blvd     |
|  3   |  2           |  717 Fourth Ave  |
+------+--------------+------------------+
代码语言:javascript
复制
Orders
+-----------------------------------+
|  Id  |  CustomerId  |  AddressId  |
+-----------------------------------+
|  1   |  1           |  1          |
|  2   |  2           |  3          |
|  3   |  1           |  3          |  <--- Invalid Customer/Address Pair
+-----------------------------------+

请注意,最终Order将客户链接到不属于他们的地址。我正在寻找一种方法来防止这种情况发生。

(你可能会问为什么我需要CustomerIdOrders表格中显示。为了清楚起见,我认识到Address已经提供了相同的信息而没有无效对的可能性。但是,我宁愿做一个Order扁平的,这样我就不会必须通过地址来检索客户。)

从我能够找到的相关阅读中,似乎一种方法可能是启用CHECK针对用户定义函数的约束。此用户定义的函数将类似于以下内容:

代码语言:javascript
复制
WHERE EXISTS (SELECT 1 FROM Addresses WHERE Id = Order.AddressId AND CustomerId = Order.CustomerId)

虽然我想象这会工作,因为我的文章有点“普遍性” 能找到的,我不觉得完全有信心,这是我最好的选择。

另一种可能是,除去CustomerId从柱Addresses完全表,而是添加另一个表IdCustomerIdAddressId。然后Order会引用 Id。再一次,我不喜欢通过辅助表来获取一个Customer或多个的想法Address

有更清洁的方法吗?或者我只是简单地说这一切都错了?

EN

回答 2

Stack Overflow用户

发布于 2019-05-30 09:22:11

好问题,但从根本上看,你似乎正在努力创建一个非外键的东西的外键约束:

Orders.CustomerId -> Addresses.CustomerId

没有简单的内置方法可以做到这一点,因为它通常没有完成。在理想的RDBMS的做法,你应该力争在自己的表来封装特定类型的数据。换句话说,尽量避免冗余数据。

在上面的示例情况中,地址所有权在地址表和订单表中都是多余的,因此需要进行额外的检查以使它们保持同步。这可能很容易与更大的数据集失控。

你提到过:

但是,我更倾向于将订单展平,以便我不必通过地址来检索客户。

但这就是关系数据库是关系数据库的原因。它这样做是为了使不同的数据可以保持不同并用相对ID引用。

我认为最好的解决方案就是放弃这个要求。

换句话说,只需:

代码语言:javascript
复制
Customers
+---------------+
|  Id  |  Name  |
+---------------+
|  1   |  Sam   |
|  2   |  Jane  |
+---------------+
代码语言:javascript
复制
Addresses
+----------------------------------------+
|  Id  |  CustomerId  |  Address         |
+----------------------------------------+
|  1   |  1           |  105 Easy St     |
|  2   |  1           |  9 Gale Blvd     |
|  3   |  2           |  717 Fourth Ave  |
+------+--------------+------------------+
代码语言:javascript
复制
Orders
+--------------------+
|  Id  |  AddressId  |
+--------------------+
|  1   |  1          |
|  2   |  3          |
|  3   |  3          |  <--- Valid Order/Address Pair
+--------------------+
票数 0
EN

Stack Overflow用户

发布于 2019-05-30 10:38:27

你可能会问,为什么我需要CustomerIdOrders表都没有。为了清楚起见,我认识到Address已经为我提供了相同的信息而没有无效对的可能性。但是,我更喜欢Order扁平化,以便我不必通过地址来检索客户。

如果遇到性能问题,首先要创建或修改正确的索引。DBMS通常擅长连接操作(具有适当的索引)。但是,规范化有时可以帮助进行性能调优。但它应该是最后的手段。如果采取这种方式,人们应该真正知道自己在做什么,并且要非常小心,不要在一天结束时损坏更多,一个人已经获得了。我怀疑,你在这里没有选择,真的需要走那条路。你可能会咆哮错误的树。因此,我建议你把“正常”,“理智”的方式,只是下降customeridorders,并创建适当的索引。

但是,如果你真的坚持,你可以尝试创建(id, customerid)一个密钥addresses(使用一个唯一的约束),然后根据它创建一个外键。

代码语言:javascript
复制
ALTER TABLE addresses
            ADD UNIQUE (id,
                        customerid);

ALTER TABLE orders
            ADD FOREIGN KEY (addressid,
                             customerid)
                            REFERENCES addresses
                                       (id,
                                        customerid);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100009065

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档