2010-10-06 15 views
3

je dois avoir une table dans T-SQL qui aura la structure suivanteContraintes dans la base de données SQL

KEY  Various_Columns  Flag 
1   row 1    F 
2   row_2    F 
3   row_3    T 
4   row_4    F 

Soit aucune ligne, ou au plus une ligne peut avoir la colonne de drapeau avec la valeur T. Mon développeur affirme que cela peut être réalisé avec une contrainte de vérification placé sur la table.

Questions:

  1. Est-ce qu'une telle contrainte être mis sur la base de données elle-même (par exemple une contrainte entre les rangs) au niveau de la base de données, plutôt que dans les règles commerciales pour la mise à jour ou insérer des lignes
  2. Est-ce une table en forme normale?
  3. Ou une forme normale nécessiterait la suppression de la colonne Flag, et à la place (disons) une autre table ou variable simple contenant la valeur de row qui avait Flag = T, ie dans la ligne case = 3 ci-dessus.
+2

Quelle version de SQL Server, s'il vous plaît? – gbn

+0

Actuellement, Microsoft SQL Server 2005 – DACN

+0

Juste au cas où il s'agit d'une liste de 'réponses' à une 'questions' vous pouvez simplement enregistrer la bonne réponse avec la question et toutes les fausses réponses dans une table. Une seule vraie réponse non répétitive est directement liée à la clé primaire d'une question. Je pensais juste que je mentionnerais que le motif semblait familier. –

Répondre

7

1 Non. Une contrainte de vérification est par ligne. Aucune autre contrainte ne le fera non plus.

, il vous faut:

  • un déclencheur (toutes les versions)
  • de vue indexée avec filtre Flag = T et index unique sur Flag (SQL Server 2000+)
  • index filtré (SQL serveur 2008)

2 assez bon

3 Overkill vraiment. Vous divisez les mêmes données pour éviter les solutions ci-dessus. Mais en utilisant une table d'une rangée, FK pour les colonnes d'identité, et une contrainte unique sur le drapeau

+0

+1 index filtré sont plus simples lorsqu'ils sont disponibles –

+0

Avant l'index filtré dans SQL Server 2008, vous pouviez utiliser des vues séparées en utilisant 'WITH CHECK OPTION' et exiger que les utilisateurs se mettent à jour via les vues plutôt que la table de base. Moins qu'idéale, elle montre qu'il existe généralement plusieurs façons de dépecer un chat (voir ma réponse pour d'autres façons). Méfiez-vous des phrases telles que: "Vous avez besoin d'une de ";) – onedaywhen

0

Mon développeur prétend que cela peut être réalisé avec une contrainte de vérification placé sur la table.

SQL Server ne pas directement ** sous-requêtes de soutien en CHECK contraintes (une exigence pour SQL-92 complète, seul SQL Server est compatible avec niveau d'entrée SQL-92, d'une manière générale). Bien qu'il y ait certainement de meilleurs moyens d'imposer cette contrainte dans SQL Server, il est possible de réaliser une contrainte pure et simple en utilisant une contrainte CHECK au niveau de la ligne et une contrainte UNIQUE par exemple. voici une façon:

CREATE TABLE YourStuff 
(
key_col INTEGER NOT NULL UNIQUE, 
Various_Columns VARCHAR(8) NOT NULL, 
Flag CHAR(1) DEFAULT 'F' NOT NULL 
    CHECK (Flag IN ('F', 'T')), 
Flag_key INTEGER UNIQUE, 
CHECK (
     (Flag = 'F' AND Flag_key = key_col) 
     OR 
     (Flag = 'T' AND Flag_key = NULL) 
     ) 
); 

La question ici est que vous aurez besoin de maintenir les valeurs de colonne Flag_key « manuellement ». Remplacement de la colonne + CHECK avec une colonne calculée signifierait que les valeurs sont maintenues automatiquement:

CREATE TABLE YourStuff 
(
key_col INTEGER NOT NULL UNIQUE, 
Various_Columns VARCHAR(8) NOT NULL, 
Flag CHAR(1) DEFAULT 'F' NOT NULL 
    CHECK (Flag IN ('F', 'T')), 
Flag_key AS (
       CASE WHEN Flag = 'F' THEN key_col 
        ELSE NULL END 
      ), 
UNIQUE (Flag_key) 
); 

** Bien que SQL Server ne directement sous-requêtes de soutien à CHECK contraintes, il existe une solution dans certains en utilisant une fonction définie par l'utilisateur (UDF)

CREATE FUNCTION dbo.CountTFlags() 
RETURNS INTEGER 
AS 
BEGIN 
DECLARE @return INTEGER; 
SET @return = (
       SELECT COUNT(*) 
       FROM YourStuff 
       WHERE Flag = 'T' 
      ); 
RETURN @return; 
END; 

CREATE TABLE YourStuff 
(
key_col INTEGER NOT NULL UNIQUE, 
Various_Columns VARCHAR(8) NOT NULL, 
Flag CHAR(1) DEFAULT 'F' NOT NULL 
    CHECK (Flag IN ('F', 'T')), 
CHECK (1 >= dbo.CountTFlags()) 
); 

Notez que l'approche UDF ne fonctionnera pas dans tous les cas et que la prudence est requise. Le point important est que les fonctions UDF seront évaluées pour chaque ligne affectée (plutôt que pour l'instruction SQL ou le niveau de transaction, comme vous pouvez vous y attendre). Dans ce cas, la contrainte doit être vraie pour chaque ligne affectée et donc - je pense! -- c'est sûr. Pour plus de détails, voir Trouble with CHECK Constraints by David Portas.


Personnellement, je voudrais simplement utiliser une deuxième table pour modéliser Flag, qui ne concernent que les clés et une clé étrangère par exemple

CREATE TABLE YourStuff 
(
key_col INTEGER NOT NULL UNIQUE, 
Various_Columns VARCHAR(8) NOT NULL 
); 

CREATE TABLE YourStuffFlag 
(
key_col INTEGER NOT NULL UNIQUE 
    REFERENCES YourStuff (key_col) 
); 

Est table [ma] sous forme normale?

Vous devriez en visant la forme normale cinquième (5NF). Si vous avez réalisé cela dépend de la conception de Various_Columns. Je ne crois pas que votre Flag tombe la volaille des exigences pour 5NF et je ne vois aucune mise à jour, supprimer ou insérer des anomalies (qui est le point de normalisation, mais une conception 5NF peut encore présenter des anomalies). Cela dit, pour changer la ligne qui obtient le flag attibute, ma conception à deux tables nécessite une seule instruction UPDATE alors que votre conception de table unique en nécessite deux;)

+0

Merci pour l'entrée et les solutions astucieuses de l'utilisation unique avec un "champ drapeau numérique" à côté du "champ de drapeau approprié". – DACN

+1

Ma préférence de toutes les solutions est d'utiliser une deuxième table contenant l'index de ma rangée de drapeau. – DACN

Questions connexes