2010-10-22 18 views
5

J'ai une table, quelque chose commeUNIQUE contrôlée par une colonne de bits

FieldsOnForms(
FieldID int (FK_Fields) 
FormID int (FK_Forms) 
isDeleted bit 
) 

La paire (FieldID, FormID) doit être unique, mais seulement si la ligne n'est pas supprimé (isDeleted = 0).

Est-il possible de définir une telle contrainte dans SQLServer 2008? (sans utiliser de déclencheurs)

P.S. Définir (FieldID, FormID, isDeleted) comme unique ajoute la possibilité de marquer une ligne comme supprimée, mais j'aimerais avoir la possibilité de mettre n lignes (par FieldID, FormID) à isDeleted = 1, et d'en avoir seulement une avec isDeleted = 0

Répondre

12

vous pouvez avoir un index unique de, en utilisant SQL Server 2008 filtered indexes fonction, ou vous pouvez appliquer un index UNIQUE sur une vue (l'index filtré pauvre homme, travaille contre les versions antérieures), mais vous ne pouvez pas avoir une contrainte UNIQUE telle que vous l'avez décrite.

Un exemple de l'index filtré:

CREATE UNIQUE NONCLUSTERED INDEX IX_FieldsOnForms_NonDeletedUnique ON FieldsOnForms (FieldID,FormID) WHERE isDeleted=0 
+0

+1 meilleure réponse ... – gbn

+0

Bien que je rencontre des erreurs, à cause du champ de bits (Convertir une colonne en type de données d'une constante n'est pas supporté pour les index filtrés), cela semble être le solution que je recherchais. – jaraics

+0

@jaraics - Je viens de créer la table dans votre question, puis l'index dans ma réponse, et il est créé sans erreur. En outre, si vous rencontrez des discordances de type de données, il est généralement préférable de CAST (ou CONVERT) la constante du type de colonne, plutôt que l'inverse. Je ne sais pas si cela réglerait votre problème. –

1

Non, vraiment unique moyen unique. Vous devrez déplacer vos enregistrements supprimés vers une autre table ou modifier IsDeleted pour qu'il puisse être unique dans tous les enregistrements supprimés (par exemple, un horodatage). Chaque solution nécessitera un travail supplémentaire dans votre application, dans une procédure stockée ou dans un déclencheur.

2

Vous pouvez modifier votre colonne IsDeleted en DeletedDate et en faire une DATETIME avec l'heure exacte à laquelle la ligne a été supprimée logiquement. Vous pouvez également ajouter une colonne DeletedDate, puis créer une colonne IsDeleted calculée pour que cette colonne soit toujours disponible si elle est utilisée dans le code. Vous devrez alors mettre un index unique sur DeletedDate (en plus de FieldID et FormId) au lieu de la colonne IsDeleted. Cela permettrait exactement une colonne NULL. Albin a publié une solution similaire à celle-ci, mais l'a ensuite supprimée. Je ne sais pas pourquoi, mais s'il le re-publie alors il était ici avant le mien. :)

+0

Cela semble être une bonne alternative pour les serveurs SQL antérieurs. – jaraics