J'ai les tableaux suivants dans un serveur SQL 2008 dB: p>
tblitem strong>, qui a un champ fort> itemID strong>; p> li>
tblgooditem strong>, qui a également un champ d'élémentId, et a une clé étrangère pointant vers TBLITEM; P> LI>
tblbaditem strong>, qui a également un champ d'élémentId, et a également une clé étrangère pointant vers TBLITEM. P> LI>
ul>
Un élément ne peut pas être à la fois un bon article et un mauvais article; Ce doit soit être celui ou l'autre. Cependant, si l'article est bon ou mauvais, ce doit être un élément. P>
Ma question est la suivante: Comment puis-je ajouter une contrainte aux champs ItemID dans Tblgooditem et TblbAditem afin qu'une valeur ITPORT ne puisse exister dans les deux tables forte>? P>
J'ai lu des réponses dans une dépassement de pile sur des questions similaires et je pense à cette solution: p>
Créer une vue Écrivez un UDF fnitem strong> qui fait une requête sur Vwitem pour voir combien d'enregistrements existent à la vue. P> Li>
avoir une contrainte qui appelle FnItem et vérifie que la valeur renvoyée est 0. p> li>
ul>
est cette meilleure idée? Est-ce que quelqu'un a une meilleure idée? P>
5 Réponses :
Débarrassez-vous de Tblgooditem and TblbAditem et faites une nouvelle table avec un élémenttype = "g" ou "B" et mettre un index unique ou une clé sur l'élémentId, aucune contrainte n'est nécessaire sur Tblitem. P>
Non peut faire, j'ai peur. Les bons articles ont des propriétés que les mauvais articles n'ont pas, et inversement.
S'il n'y a que quelques-uns, moins de 10 différences, alors je les combine toujours, faites-les permettre à NULL et ajoutez une contrainte de contrôle pour les exiger en fonction de la colonne Type
Vous ne pouvez pas utiliser une instruction code> SELECT CODE> dans un Je pense que votre meilleure option serait de Écrivez un laissez-passer UDF dans l'itemID et vérifiez s'il existe. Pour ce scénario, c'est vraiment l'option la plus simple. P> J'ai ajouté des données de test et un exemple de fonction. P> vérifier code> contrainte - ce n'est pas vraiment ce qu'ils ont été conçus pour.
CREATE FUNCTION dbo.fn_CheckItems(@itemId INT) RETURNS BIT
AS BEGIN
DECLARE @i INT,
@rv BIT
SET @i = 0
IF (SELECT COUNT(*) FROM tblBadItem WHERE ItemId = @ItemId) > 0
BEGIN
SET @i = 1
END
IF (SELECT COUNT(*) FROM tblGoodItem WHERE ItemId = @ItemId) > 0
BEGIN
SET @i = @i + 1
END
IF (@i > 1)
BEGIN
SET @rv = 1
END
ELSE
BEGIN
SET @rv =0
END
RETURN @rv
END
GO
CREATE TABLE tblItem (
ItemID INT IDENTITY(1,1) PRIMARY KEY,
DateAdded DATETIME
)
GO
CREATE TABLE tblGoodItem (
ItemID INT PRIMARY KEY,
CHECK (dbo.fn_CheckItems(ItemId) = 0)
)
GO
CREATE TABLE tblBadItem (
ItemID INT PRIMARY KEY,
CHECK (dbo.fn_CheckItems(ItemId) = 0)
)
GO
INSERT INTO tblItem (DateAdded)
VALUES (GETDATE())
INSERT INTO tblGoodItem(ItemID)
SELECT ItemId FROM tblItem
--This statement will fail as the ItemId is already in GoodItems
INSERT INTO tblBadItem(ItemID)
SELECT ItemId FROM tblItem
DROP TABLE tblItem
DROP TABLE tblGoodItem
DROP TABLE tblBadItem
DROP FUNCTION dbo.fn_CheckItems
@Alexkuznetsov - Pourriez-vous élaborer pourquoi cela ne fonctionnera pas. J'ai créé un test et ça marche bien?
Mes excuses, j'avais tort. Cependant, de tels UDF sont très lents et si vous utilisez l'isolement de l'instantané, vous pouvez obtenir des résultats de manière sporadiquement sous concurrence.
@Alexkuznetsov - Pas de problème. Je dois admettre que je n'ai pas utilisé cela tout en utilisant la réplication de l'instantané, je ne pouvais donc pas être en désaccord ni être d'accord avec cela.
Je ne comprends probablement pas vos exigences de votre entreprise ici, mais pourquoi souhaitez-vous avoir une table séparée pour les bons et les mauvais éléments? Sont-ils non pas des abstractions de la même chose? P>
Pourquoi ne pas utiliser un drapeau ISBADITEM ou plus spécifiquement une colonne ItemConditionStatus. P>
Ajouter une colonne Tblitem.Itempltype. Cette colonne ne peut avoir qu'une seule valeur sur une ligne donnée (évidemment). Ajoutez une contrainte unique sur l'élémentId, itemType.
Maintenant le truc: Peu de gens se souviennent de cela, mais une clé étrangère peut faire référence aux colonnes d'une contrainte unique. P>
CREATE TABLE tblItem ( ItemID INT PRIMARY KEY, ItemType CHAR(1), UNIQUE KEY (ItemID, ItemType) ); CREATE TABLE tblGoodItem ( ItemID INT PRIMARY KEY, ItemType CHAR(1), CHECK (ItemType='G') FOREIGN KEY (ItemID, ItemType) REFERENCES tblItem(ItemID, ItemType) ); CREATE TABLE tblBadItem ( ItemID INT PRIMARY KEY ItemType CHAR(1), CHECK (ItemType='B') FOREIGN KEY (ItemID, ItemType) REFERENCES tblItem(ItemID, ItemType) );
Vous m'avez battu de quelques secondes.
J'aime beaucoup cette idée. Pas besoin de s'inquiéter de changer de mauvais au bien - en fait, je ne veux pas que ce changement se produise.
dans TBLITEM, ajoutez la colonne d'optionType. Avoir une contrainte de vérification pour vous assurer que l'élément est bon ou mauvais. Créez une contrainte unique sur (ItemID, ItemType) P>
Ajouter une colonne d'optionType à la fois aux tables de mauvaises et bonnes options. Avoir une contrainte de contrôle pour vous assurer que l'élémenttype est bon dans une bonne table et une mauvaise table dans une mauvaise table. P>