2010-06-12 7 views
1

J'ai deux tables:CONTRAINTE UNIQUE sur une colonne de la table étrangère dans SQL Server 2008


create table [dbo].[Main] 
(
    [ID] [int] identity(1,1) primary key not null, 
    [No] [int] not null, 
    [Sign] [char](1) not null 
) 

create table [dbo].[Names] 
(
    [ID_Main][int] primary key not null, 
    [Name][nvarchar](128) not null, 
    constraint [FK_Main_Users] foreign key ([ID_Main]) references [dbo].[Main]([ID]), 
    constraint [CK_Name] unique ([Name], [Sign]) 
) 

Le problème est avec la deuxième contrainte CK_Name

Y at-il un moyen de faire une colonne cible de contrainte de une table étrangère?



EDIT:



Explication. J'utilise ces tables dans une application Silverlight en utilisant EntityFramework. Les entités sont créées par le tableau par héritage de type de sorte que le code est quelque chose comme ceci:


public abstract class Main 
{ 
    // main properties 
} 

public class Names : Main 
{ 
    // names properties 
} 

Cela me force à ne pas utiliser des vues SQL.

Données d'échantillon.

 
--------------------------------------------- 
| Main    | Names    | 
--------------------------------------------- 
| ID | Sign | No | ID_Main | Name | 
--------------------------------------------- 
| 1 |  A | 1 | 1  | 'qwe' | 
| 2 |  B | 1 | 2  | 'qwe' | 
| 3 |  B | 1 | 3  | 'qwe' | 
| 4 |  C | 1 | 4  | 'qwe' | 
| 5 |  A | 2 | 5  | 'asd' | 
| 6 |  B | 2 | 6  | 'asd' | 
| 7 |  B | 2 | 7  | 'asd' | 
| 8 |  C | 2 | 8  | 'asd' | 

Comme vous pouvez le voir, il y a quelques lignes avec le même nom mais avec des signes. Il ne peut pas y avoir de nom non unique avec le même signe.

Je voudrais faire valoir qu'il n'y a qu'un seul nom avec signe = A et un seul nom avec l'écriteau C mais beaucoup de noms avec le signe = B

+3

Pourquoi? – LukLed

+0

Compte tenu des informations supplémentaires que vous avez fournies, j'aimerais en savoir plus sur les raisons pour lesquelles vous souhaitez cette restriction. Quelles entités représentent 'Main' et' Names'? Compte tenu de l'exemple de sortie, la table 'Names' ressemble à une table intermédiaire, sauf que' ID_Main' est un PK, donc il est réellement appliqué en tant que relation 1: 1. Quelles sont les règles par lesquelles il est déterminé qu'un signe ne peut avoir qu'un nom mais qu'un autre signe peut avoir plusieurs noms? – Thomas

+0

Presque toutes les tables de mon système ont plusieurs colonnes communes. Je les ai donc placées dans une table principale et d'autres tables s'y réfèrent. Oui, il semble être une relation 1: 1, mais une autre logique en fait un 1: * mais pas directement – bodziec

Répondre

4

Oui, vous pouvez appliquer cette contrainte en utilisant vue indexée et la création une contrainte unique (index) sur (Sign, Name) pour le jeu de résultats filtré.

CREATE VIEW dbo.vwSelectiveUniqueSignName WITH SCHEMABINDING 
AS 
SELECT [Sign], Name 
FROM  
    dbo.Main INNER JOIN dbo.Names on ID = ID_Main 
WHERE 
    dbo.Main.Sign IN ('A', 'C') 
GO 

CREATE UNIQUE CLUSTERED INDEX IDX_vwSelectiveUniqueSignName_Unique_Sign_Name 
    ON dbo.vwSelectiveUniqueSignName ([Sign] ASC, Name ASC) 
GO 

Test:

-- using your sample data: 
/* Case 1 Sign = 'A', Name = 'qwe': this will throw error 'cannot insert duplicate key row in object ... with unique index ... */ 
BEGIN TRAN NotAllowedMoreThan_1 
insert dbo.Main ([Sign]) OUTPUT inserted.* values ('A') /* same for 'C' */ 
insert dbo.Names (ID_Main, Name) OUTPUT inserted.* SELECT SCOPE_IDENTITY(),'qwe' 
COMMIT TRAN NotAllowedMoreThan_1 
GO 

/* Case 2 Sign = 'B', Name = 'qwe': this will pass > 1 times (note GO loop) */ 
BEGIN TRAN AllowedMoreThan_1 
insert dbo.Main ([Sign]) OUTPUT inserted.* values ('B') /* any other than A, C */ 
insert dbo.Names (ID_Main, Name) OUTPUT inserted.* SELECT SCOPE_IDENTITY(),'qwe' 
COMMIT TRAN AllowedMoreThan_1 
GO 2 
+0

J'ai modifié mon post avec plus d'explications. Les contraintes sur les vues fonctionnent même si je n'utilise pas de vues? – bodziec

+0

Oui, la contrainte empêchera l'insertion d'enregistrements non uniques dans les tables. –

+0

Ok, votre réponse et cet article http://dbwhisperer.blogspot.com/2008/11/adding-check-constraint-to-view.html m'a aidé à trouver une solution à mon problème. Si vous êtes si gentil et éditez votre message en changeant la définition des vues qu'il montre seulement les noms des rangées avec 'A' et ajoutez un index unique dessus je marquerai ceci comme réponse – bodziec

1

Pour répondre à votre question, il n'y a pas moyen de faire référence à une colonne dans une table étrangère dans une contrainte de vérification (ou tout autre type de contrainte pour cette matière). Cependant, dans votre situation, vous voulez vous assurer que toute combinaison de Names.Name et Main.Sign sera unique. Pour ce faire, vous pouvez simplement ajouter une contrainte unique sur chacune des deux colonnes:

Alter Table dbo.Main Add Constraint UC_Main Unique Nonclustered (Sign) 
GO 
Alter Table dbo.Names Add Constraint UC_Names Unique Nonclustered (Name) 

Il n'y a pas besoin de créer une contrainte unique sur ID_Main et nom ensemble depuis ID_Main est déjà nécessaire d'être unique par sa clé primaire contrainte. Pourquoi pas `[Name, ID_Main]` et un unique supplémentaire sur `[Sign]` dans la table [Main] `

+0

J'ai modifié mon message avec plus d'explications – bodziec

Questions connexes