我正在使用Microsoft SQL Server 2017,并对如何约束特定关系感到好奇。我在表达方面遇到了一些麻烦,所以我宁愿通过一个例子来分享。
请考虑以下假设数据库。
Customers
+---------------+
| Id | Name |
+---------------+
| 1 | Sam |
| 2 | Jane |
+---------------+
Addresses
+----------------------------------------+
| Id | CustomerId | Address |
+----------------------------------------+
| 1 | 1 | 105 Easy St |
| 2 | 1 | 9 Gale Blvd |
| 3 | 2 | 717 Fourth Ave |
+------+--------------+------------------+
Orders
+-----------------------------------+
| Id | CustomerId | AddressId |
+-----------------------------------+
| 1 | 1 | 1 |
| 2 | 2 | 3 |
| 3 | 1 | 3 | <--- Invalid Customer/Address Pair
+-----------------------------------+
请注意,最终Order
将客户链接到不属于他们的地址。我正在寻找一种方法来防止这种情况发生。
(你可能会问为什么我需要CustomerId
在Orders
表格中显示。为了清楚起见,我认识到Address
已经提供了相同的信息而没有无效对的可能性。但是,我宁愿做一个Order
扁平的,这样我就不会必须通过地址来检索客户。)
从我能够找到的相关阅读中,似乎一种方法可能是启用CHECK
针对用户定义函数的约束。此用户定义的函数将类似于以下内容:
WHERE EXISTS (SELECT 1 FROM Addresses WHERE Id = Order.AddressId AND CustomerId = Order.CustomerId)
虽然我想象这会工作,因为我的文章有点“普遍性” 是能找到的,我不觉得完全有信心,这是我最好的选择。
另一种可能是,除去CustomerId
从柱Addresses
完全表,而是添加另一个表Id
,CustomerId
,AddressId
。然后Order
会引用它 Id
。再一次,我不喜欢通过辅助表来获取一个Customer
或多个的想法Address
。
有更清洁的方法吗?或者我只是简单地说这一切都错了?
发布于 2019-05-30 09:22:11
好问题,但从根本上看,你似乎正在努力创建一个非外键的东西的外键约束:
Orders.CustomerId -> Addresses.CustomerId
没有简单的内置方法可以做到这一点,因为它通常没有完成。在理想的RDBMS的做法,你应该力争在自己的表来封装特定类型的数据只。换句话说,尽量避免冗余数据。
在上面的示例情况中,地址所有权在地址表和订单表中都是多余的,因此需要进行额外的检查以使它们保持同步。这可能很容易与更大的数据集失控。
你提到过:
但是,我更倾向于将订单展平,以便我不必通过地址来检索客户。
但这就是关系数据库是关系数据库的原因。它这样做是为了使不同的数据可以保持不同并用相对ID引用。
我认为最好的解决方案就是放弃这个要求。
换句话说,只需:
Customers
+---------------+
| Id | Name |
+---------------+
| 1 | Sam |
| 2 | Jane |
+---------------+
Addresses
+----------------------------------------+
| Id | CustomerId | Address |
+----------------------------------------+
| 1 | 1 | 105 Easy St |
| 2 | 1 | 9 Gale Blvd |
| 3 | 2 | 717 Fourth Ave |
+------+--------------+------------------+
Orders
+--------------------+
| Id | AddressId |
+--------------------+
| 1 | 1 |
| 2 | 3 |
| 3 | 3 | <--- Valid Order/Address Pair
+--------------------+
发布于 2019-05-30 10:38:27
你可能会问,为什么我需要
CustomerId
在Orders
表都没有。为了清楚起见,我认识到Address
已经为我提供了相同的信息而没有无效对的可能性。但是,我更喜欢Order
扁平化,以便我不必通过地址来检索客户。
如果遇到性能问题,首先要创建或修改正确的索引。DBMS通常擅长连接操作(具有适当的索引)。但是,规范化有时可以帮助进行性能调优。但它应该是最后的手段。如果采取这种方式,人们应该真正知道自己在做什么,并且要非常小心,不要在一天结束时损坏更多,一个人已经获得了。我怀疑,你在这里没有选择,真的需要走那条路。你可能会咆哮错误的树。因此,我建议你把“正常”,“理智”的方式,只是下降customerid
的orders
,并创建适当的索引。
但是,如果你真的坚持,你可以尝试创建(id, customerid)
一个密钥addresses
(使用一个唯一的约束),然后根据它创建一个外键。
ALTER TABLE addresses
ADD UNIQUE (id,
customerid);
ALTER TABLE orders
ADD FOREIGN KEY (addressid,
customerid)
REFERENCES addresses
(id,
customerid);
https://stackoverflow.com/questions/-100009065
复制相似问题