如何防止一个表中的条目存在于另一个表中

时间:2011-05-05 10:46:11

标签: sql sql-server sql-server-2008

我在SQL Server 2008中有3个表

  • 拥有身份证号码和姓名PK的俱乐部。
  • 具有ID为PK,ClubID的FK,名称,ShortCode和关键字的产品。
    • 英国有强制要求ShortCode / Keyword组合没有重复的关键字。
  • ProductAdditionalShortCodes。它具有ID的PK,ProductID的FK和关键字

我们的想法是防止产品的任何短代码/关键字组合指向不同的分会,并防止创建重复的短/代码关键字组合

我有一个有效的解决方案,但感觉很笨,如果多个用户同时更新多个条目,在某些情况下可能会失败。 (假设)

如何向DB中添加某种形式的约束,以防止Main表中的Keyword与Additional表中的Keyword相同,反之亦然?

以下是创建场景的示例脚本以及我想要阻止的一些示例。如果变更的影响不会破坏解决方案的太多其他方面,我不反对更改数据库设计。 (我意识到这是主观的)

use Tinker

if exists (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'dbo.ProductAdditionalKeywords') AND type in (N'U'))
    drop table dbo.ProductAdditionalKeywords
go
if exists (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'dbo.Products') AND type in (N'U'))
    drop table dbo.Products
go
if exists (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'dbo.Clubs') AND type in (N'U'))
    drop table dbo.Clubs
go

create table dbo.Clubs (
     ID        int         not null identity(1,1)
    ,Name      varchar(50) not null
    ,constraint PK_Clubs primary key clustered ( ID ) 
)
go
alter table dbo.Clubs add constraint UK_Clubs__Name unique ( Name )
go
create table dbo.Products (
     ID        int         not null identity(1,1)
    ,ClubID    int         not null
    ,Name      varchar(50) not null
    ,ShortCode varchar(50) not null
    ,Keyword   varchar(50) not null
    ,constraint PK_Products primary key clustered ( ID ) 
)
go
alter table dbo.Products add constraint UK_Products__ShortCode_Keyword unique ( ShortCode , Keyword )
go
alter table dbo.Products add constraint UK_Products__Name unique ( Name )
go
alter table dbo.Products add constraint FK_Products_ClubID foreign key ( ClubID ) references dbo.Clubs ( ID )
go
create table dbo.ProductAdditionalKeywords (
     ID        int         not null identity(1,1)
    ,ProductID int         not null
    ,Keyword   varchar(50) not null
    ,constraint PK_ProductAdditionalKeywords primary key clustered ( ID ) 
)
go
alter table dbo.ProductAdditionalKeywords add constraint FK_ProductAdditionalKeywords_ProductID foreign key ( ProductID ) references dbo.Products ( ID )
go
alter table dbo.ProductAdditionalKeywords add constraint UK_ProductAdditionalKeywords__Keyword unique ( Keyword )
go

insert into dbo.Clubs ( Name )
          select 'Club 1'
union all select 'Club 2'

insert into dbo.Products (ClubID,Name,Shortcode,Keyword) 
          select 1,'Product 1','001','P1' 
union all select 1,'Product 2','001','P2'
union all select 1,'Product 3','001','P3'
union all select 2,'Product 4','002','P4' 
union all select 2,'Product 5','002','P5'
union all select 2,'Product 6','002','P6'

insert into dbo.ProductAdditionalKeywords (ProductID,Keyword)
          select 1,'P1A'
union all select 1,'P1B'
union all select 2,'P2A'
union all select 2,'P2B'

/*
 What can be done to prevent the following statements from beeing allowed based on the reason in the comments?
 */

--insert into dbo.ProductAdditionalKeywords (ProductID,Keyword) values ( 1 , 'P2' ) -- Main keyword for product 2
--update dbo.Products set Keyword =  'P1A' where ID = 2                               -- Additional keyword for product 1
--insert into dbo.ProductAdditionalKeywords (ProductID,Keyword) values ( 3 , 'P1' ) -- Main ShortCode/Keyword combination for product 1

/*
 At the moment I look at the following view to see if the proposed(new/updated) Keyword/Shortcode combination already exists
 If it already exists I pevent the insert/update
 Is there any way to do it in the DB via constraints rather than in the BLL?
 */
select ShortCode,Keyword,count([ClubID]) as ClubCount from 
(
    select p.ClubID,p.ShortCode,p.Keyword,p.ID
    from dbo.Products p
union all 
    select p.ClubID,p.ShortCode,PAK.Keyword,PAK.ID * -1
    from dbo.ProductAdditionalKeywords as PAK 
    inner join dbo.Products P on PAK.ProductID = P.ID
) as FullList
group by Shortcode,Keyword
order by Shortcode,Keyword

2 个答案:

答案 0 :(得分:2)

我通常如何将所有关键字放在一个单独的表中(例如,当前是您的附加表)。如果所有关键字在ShortCode中必须是不同的,那么我也会在此表中包含ShortCode,以便可以跨两列应用唯一约束。

如果产品的所有关键字都必须在同一个ShortCode中,那么我也会在产品中保留ShortCode。我在该表中应用了一个唯一约束(ID,ShortCode),并在关键字表中引用了另一个外键,引用了两侧的两列。

我们现在剩下的是原始设计中未包含的两个潜在问题,但我不知道它们是否在实践中受到关注:

1)产品中的关键字是否比其他关键字更重要或更特殊?如果是这样,我们需要在关键字表中添加一列来标记哪一个是重要的。为了确保只设置一个,您可以搜索大量其他涉及附加条件的唯一约束的SO问题。 (如果你找不到一个并且需要它,请告诉我,我确信如果有必要我可以添加一个链接)

2)是否应该允许产品没有关键字?如果没有,那么我将创建一个模仿原始Products表的视图。在这种情况下,如果1)以上是真的会更容易,在这种情况下,我们总是加入“重要”关键字。否则,我们需要有一些方法将其限制为每个产品一行。我们拒绝在表上插入/更新/删除,只允许它们通过视图。然后,3个相对简单的触发器将维护基础表结构。

答案 1 :(得分:0)

关于你的设计,我不明白使用没有ShortCode字段的productAdditionalShortCodes。 但是,您可以使用ShortCode& amp;添加唯一键约束。关键字(复合键)。这将消除产品表中的重复条目。