2011-11-02 3 views
4

J'utilise SQL Server 2008. J'ai une table de base de données qui ressemble à ceci (avec des colonnes sans importance omises):SQL Server Filtré Index pour unique Constraint

CREATE TABLE [dbo].[ImageDocument_FaxProperties](
    [FaxPropertyID] [int] PRIMARY KEY IDENTITY(1,1), 
    [Agent] [varchar](25) NULL, 
    [ParentImageDocumentId] [uniqueidentifier] NULL 
) 

Je veux créer une contrainte où le même L'agent peut avoir plusieurs lignes tant que les éléments ParentImageDocumentIds sont identiques sur chaque ligne, mais qu'un agent ne peut pas avoir de lignes avec des éléments ParentImageDocumentIds différents. Je comprends que ce n'est pas une bonne structure de table, mais c'est l'héritage & Je ne suis pas autorisé à le changer. NULL ParentImageDocumentIds doit être considéré comme différent.

Par exemple:

PK Agent  ParentImageDocumentId -This is ok 
# person1 {D09C3900-0300}  {.. other columns ..} 
# person1 {D09C3900-0300}  {.. other columns ..} 

PK Agent  ParentImageDocumentId -Check constraint prevents 2nd row insertion 
# person1 NULL     {.. other columns ..} 
# person1 NULL     {.. other columns ..} 

PK Agent  ParentImageDocumentId -Check constraint prevents 2nd row insertion 
# person1 NULL     {.. other columns ..} 
# person1 {A13E5B21-93DE}  {.. other columns ..} 

PK Agent  ParentImageDocumentId -Check constraint prevents 2nd row insertion 
# person1 {D09C3900-0300}  {.. other columns ..} 
# person1 {A13E5B21-93DE}  {.. other columns ..} 

Je me demande quelle est la meilleure façon d'écrire une contrainte pour cela. Un index unique sur l'agent ne fonctionnera pas, car ils peuvent parfois avoir les deux. Un unique sur l'agent, ParentImageDocumentId leur permettrait d'avoir des GUID différents, ce qui n'est pas correct. Un index filtré avec "WHERE ParentImageDocumentId IS NULL AND Agent IS NOT NULL" fonctionnera pour empêcher les valeurs NULL doubles, mais pas différents GUID ou GUID & NULL.

Ci-dessous sont deux solutions de travail, mais je me demande s'il y a une meilleure façon. Une vue schemabound indexée me permet de créer un index filtré plus compliqué. Une alternative était une contrainte de vérification au niveau de la table utilisant une fonction, cela devrait fonctionner, mais l'ajout de la contrainte de vérification est SUPER SLOW. Je devine qu'il réexécute ma fonction pour chaque ligne de la table, mais cela ne devrait pas être nécessaire pour ajouter une contrainte au niveau de la table puisque la fonction ne vérifie pas une ligne spécifique. Y a-t-il un moyen de contourner ceci? Je penche vers la vue indexée, mais je me demandais s'il y avait des alternatives (à part changer ma structure de table) & quelle alternative est la meilleure.

Solution # 1:

CREATE VIEW ImageDocument_FaxProperties_Assignments WITH SCHEMABINDING 
AS 
    SELECT Agent, ParentImageDocumentId, COUNT_BIG(*) as numPages FROM dbo.ImageDocument_FaxProperties 
    WHERE Status IN ('PROC', 'LINKING') 
    AND Agent IS NOT NULL 
    GROUP BY Agent, ParentImageDocumentId 
GO 

CREATE UNIQUE CLUSTERED INDEX [IDX_ImageDocument_FaxProperties_Assignments_Unique] ON [ImageDocument_FaxProperties_Assignments] (Agent) 
GO 

Solution # 2:

CREATE FUNCTION ImageDocument_FaxProperties_Assignments_CheckConstraint() RETURNS BIT 
AS 
BEGIN 
    DECLARE @Result BIT = 0; 
    WITH Assignments AS 
    (SELECT Agent, DENSE_RANK() OVER (PARTITION BY Agent ORDER BY ParentImageDocumentId) AS assignmentNum 
    FROM dbo.ImageDocument_FaxProperties 
    WHERE Status IN ('PROC', 'LINKING') 
    AND Agent IS NOT NULL 
    ) 

    SELECT @Result = 1 FROM Assignments WHERE assignmentNum > 1 

    RETURN @Result 
END 
GO 
ALTER TABLE [ImageDocument_FaxProperties] 
ADD CONSTRAINT ImageDocument_FaxProperties_Assignments_Unique CHECK (dbo.ImageDocument_FaxProperties_Assignments_CheckConstraint() = 0) 
+0

FWIW, solution basée sur le format UDF, a entraîné des blocages fréquents pour moi. La vue filtrée a mieux fonctionné. – Constantin

Répondre

2

La vue indexée sera la meilleure option des deux que vous proposez.

Ce type de logique dans les fonctions UDF est inefficace (est évalué pour chaque ligne) et difficile à obtenir correctement. Voir par exemple les postes suivants

+0

Wow. Excellente information dans ces liens. Je vous remercie! Je ferai certainement attention lors de l'utilisation des contraintes de vérification dans le futur. –

1

Votre autre option est d'ajouter un élément déclencheur à la table de base pour vérifier que tout ajout de données ou les modifications sont conformes aux règles spécifiées.

+0

Je suppose que je n'y avais pas pensé parce que les gens à mon travail parlent de déclencheurs comme s'ils étaient un gros mot, mais vous avez raison, ça marcherait aussi. Merci. –