Как запретить запись в одной таблице существовать в другой таблице - PullRequest
0 голосов
/ 05 мая 2011

У меня есть 3 таблицы в SQL Server 2008

  • Клубы с удостоверением личности и именем.
  • Продукты, которые имеют PK ID, FK ClubID, имя, шорткод и ключевое слово.
    • Существует Великобритания, которая обязана обеспечить отсутствие дублирующих ключевых слов для комбинаций ShortCode / Keyword.
  • ProductAdditionalShortCodes. У этого есть PK ID, FK ProductID и Ключевое слово

Идея состоит в том, чтобы запретить любую комбинацию шорткода / ключевого слова продуктов, указывающих на разные клубы, а также предотвратить создание дублированных комбинаций короткого кода / ключевого слова

У меня есть решение, которое работает, но кажется неуклюжим и может при определенных обстоятельствах потерпеть неудачу, если несколько пользователей одновременно обновили несколько записей. (Гипотетически)

Как я могу добавить какую-либо форму ограничения к БД, чтобы ключевое слово в основной таблице не совпадало с таблицей «Дополнительно» и наоборот?

Ниже приведен пример сценария для создания сценария и некоторые примеры, которые я хочу предотвратить. Я не против изменения структуры БД, если влияние этого изменения не нарушит слишком многих других аспектов решения. (Я понимаю, что это субъективно)

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 ]

2 голосов
/ 05 мая 2011

Как я обычно это делал бы, это помещало бы все ключевые слова в отдельную таблицу (например, какая сейчас ваша дополнительная таблица). Если все ключевые слова должны быть различны в ShortCode, то я бы включил ShortCode в эту таблицу, так что уникальное ограничение может быть применено к обоим столбцам.

Если все ключевые слова для продукта должны быть в одном и том же ShortCode, то я бы оставил ShortCode в продуктах. Я бы применил уникальное ограничение на (ID, ShortCode) в этой таблице и дополнительный внешний ключ из таблицы ключевых слов, ссылаясь на оба столбца с обеих сторон.

Теперь у нас остались две потенциальные проблемы, не включенные в ваш оригинальный дизайн, но я не знаю, являются ли они проблемой на практике:

1) Является ли ключевое слово в продуктах более важным или особенным, чем дополнительные ключевые слова? Если это так, нам нужно добавить столбец в таблицу ключевых слов, чтобы отметить, какой из них важен. Чтобы убедиться, что задан только один, вы можете искать множество других вопросов SO, которые включают уникальные ограничения с дополнительными условиями. (Дайте мне знать, если вы не можете найти и нуждаетесь в нем, я уверен, что при необходимости смогу добавить ссылку)

2) Нужно ли разрешать продукту не иметь ключевых слов? Если нет, то я бы создал представление, которое имитирует вашу исходную таблицу продуктов. В этом случае было бы проще, если бы 1) выше было верно, и в этом случае мы всегда присоединяемся к ключевому слову «важное». В противном случае нам нужен какой-то способ ограничить его одной строкой для каждого продукта. Мы запрещаем вставку / обновление / удаление таблицы и разрешаем их только через просмотр. 3 относительно простых триггера будут поддерживать структуру таблицы.

0 голосов
/ 05 мая 2011

в вашем дизайне, я не понимаю, использование productAdditionalShortCodes без поля ShortCode.Однако вы можете добавить ограничение уникального ключа с помощью ShortCode & Keyword (составной ключ).Это исключит дублирование записи в таблице товаров

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...