简体   繁体   English

在SQL Server中,如何在层次结构模型中强制使用唯一的孙名称?

[英]In SQL Server, how to enforce unique grandchild names in a hierarchy model?

Model: merchants have one to many customers and customers have one to many accounts. 模式:商家拥有一对多客户,客户拥有一对多帐户。 Accounts have names. 帐户有名称。 All three tables have unique IDs for each row. 所有三个表的每一行都有唯一的ID。

Constraint: For a given merchant, the account names must be unique. 约束:对于给定的商人,帐户名称必须唯一。

How do we enforce this constraint in a SQL Server database schema? 我们如何在SQL Server数据库架构中强制执行此约束?

Here'some ideas we've considered: 我们考虑过以下一些想法:

  • We could add MerchantId to the Account table and create a unique constraint, but it's a redundant column to maintain given that CustomerId is already there. 我们可以将MerchantId添加到Account表中并创建一个唯一约束,但是鉴于CustomerId已经存在,这是一个多余的列。 We'd need to make sure the combination of MerchantId and CustomerId are themselves consistent, so we'd make the foreign key between Account and Customer include both columns, even though CustomerId is already a unique identifier. 我们需要确保MerchantId和CustomerId的组合本身是一致的,因此即使CustomerId已经是唯一的标识符,我们也要使Account和Customer之间的外键包括这两个列。
  • We could add a check constraint to the Account table and use a UDF to check the constraint rule. 我们可以在“帐户”表中添加检查约束,并使用UDF来检查约束规则。 But then a Customer could conceivable be assigned to a different Merchant, and the check constraint on Account wouldn't be checked. 但是,可以想象将客户分配给其他商家,并且不会检查对帐户的检查约束。 So we'd have to add another constraint on the Customer table, which starts to seem like we're doing it wrong, especially as the real model gets more complex than described here. 因此,我们必须在Customer表上添加另一个约束,这似乎使我们做错了,尤其是当实际模型变得比此处描述的复杂时。
  • We could enforce the constraint via triggers, but this doesn't seem to improve upon the shortcomings with using check constraints. 我们可以通过触发器来强制执行约束,但是对于使用检查约束的缺点似乎并没有改善。

Maybe the best idea of a solution is to create a view joining the 3 tables and create a unique index on that view. 解决方案的最佳方法可能是创建一个连接3个表的视图,并在该视图上创建唯一索引。 That would be an indexed view . 那将是一个索引视图 When you index a view it gets persisted just like a regular table, but it's updated automagically by the database engine as part of regular DML commands. 当您为视图建立索引时,它会像常规表一样持久保存,但是数据库引擎会作为常规DML命令的一部分自动对其进行更新。

There are lots of requirements and restrictions on what you can and cannot do, those are in the docs I linked to above, but I think you can get away with it. 关于可以做什么和不能做什么的要求和限制很多,这些都在我上面链接的文档中,但是我认为您可以摆脱。

The code would go like this: 代码如下:

CREATE VIEW dbo.MerchantAccounts
WITH SCHEMABINDING
AS
    SELECT m.MerchantKey, a.AccountKey, a.Name
    FROM dbo.Accounts a
    INNER JOIN dbo.Customers c
        ON a.CustomerKey = c.CustomerKey
    INNER JOIN dbo.Merchants m
        ON c.MerchantKey = m.MerchantKey;
GO

CREATE UNIQUE CLUSTERED INDEX IX_MerchantKey_AccountName
ON dbo.MerchantAccounts (MerchantKey, Name);
GO

I included 3 columns in the view but only 2 are part of the unique clustered index. 我在视图中包括了3列,但是唯一聚集索引中只有2列。 So you must not have duplicated MarchantKey,AccountName to begin with, and after that the database engine will ensure that for you. 因此MarchantKey,AccountName开始时一定不要重复MarchantKey,AccountName ,然后数据库引擎将为您确保这一点。

You don't need to change your table and your relationships as long as you don't violate the requirements. 只要您不违反要求,就不需要更改表和关系。

You can include more columns than just the key columns in your indexes view, and that can help performance for some queries. 您可以在索引视图中包括多个列,而不仅仅是关键列,这可以帮助提高某些查询的性能。 That's up to you. 随你(由你决定。 Just be aware that the resultset of the view (the equivalent of SELECT * FROM dbo.MerchantAccounts ) will be persisted on your database and will take up space. 只需注意,视图的结果集(相当于SELECT * FROM dbo.MerchantAccounts )将SELECT * FROM dbo.MerchantAccounts在您的数据库中并占用空间。 So the more columns you add the bigger the view gets and the more expensive it gets to maintain it up to date. 因此,您添加的列越多,视图就越大,并且保持最新状态也就越昂贵。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM