2010-09-16 29 views
7

मैं एक एसक्यूएल सर्वर में निम्न तालिकाओं है 2008 db:मेरे पास एक चेक बाधा कैसे है जो किसी अन्य तालिका को संदर्भित करती है?

  • tblItem है, जो एक ItemID क्षेत्र है;

  • tblGoodItem, जिसमें एक आइटम आईडी फ़ील्ड भी है, और इसमें एक विदेशी कुंजी है जो tblItem को इंगित करती है;

  • tblBadItem है, जो भी एक ItemID क्षेत्र है, और यह भी tblItem के लिए एक विदेशी कुंजी की ओर इशारा करते हैं।

कोई आइटम एक अच्छी वस्तु और बुरी वस्तु दोनों नहीं हो सकता है; यह या तो एक या दूसरे होना चाहिए। हालांकि, क्या आइटम अच्छा या बुरा है, यह एक आइटम होना चाहिए। कैसे मैं दोनों tblGoodItem और tblBadItem में ItemID क्षेत्रों के लिए एक बाधा जोड़ सकता हूँ, ताकि एक ItemID मूल्य दोनों तालिकाओं में मौजूद नहीं कर सकते हैं:

मेरा प्रश्न है?

मैं इसी तरह के सवाल पर स्टैक ओवरफ़्लो में कुछ उत्तर पढ़ा है, और मैं इस समाधान के बारे में सोच रहा हूँ:

  • एक दृश्य vwItem जो ItemID पर tblBadItem पर tblGoodItem मिलती है बनाएँ।

  • एक यूडीएफ fnItem लिखें जो vwItem पर एक प्रश्न करता है यह देखने के लिए कि दृश्य में कितने रिकॉर्ड मौजूद हैं।

  • की कोई समस्या जो fnItem कॉल करता है और पुष्टि करता है कि दिए गए मान 0.

यह सबसे अच्छा विचार है है है? क्या किसी के पास बेहतर विचार है?

उत्तर

9

एक कॉलम tblItem.ItemType कॉलम जोड़ें।इस कॉलम में किसी भी पंक्ति (स्पष्ट रूप से) पर केवल एक मान हो सकता है। ItemID, ItemType पर एक अनूठी बाधा जोड़ें।

अब चाल: कुछ लोगों को यह याद है, लेकिन एक विदेशी कुंजी एक अद्वितीय बाधा के कॉलम का संदर्भ दे सकती है।

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) 
); 

आप एक निश्चित मूल्य के बच्चे तालिकाओं में से प्रत्येक में itemtype विवश है, तो tblItem में किसी पंक्ति केवल एक ही बच्चा तालिका से संदर्भित किया जा सकता है।

  1. हटाएँ पंक्ति tblGoodItem
  2. से
  3. tblItem में अद्यतन पंक्ति के itemtype
  4. सम्मिलित करें पंक्ति tblBadItem
  5. में
:

यह एक तीन चरणों की प्रक्रिया अच्छा से बुरा के लिए एक आइटम बदलने के लिए, हालांकि

+0

आपने मुझे कुछ सेकंड तक हराया। –

+0

मुझे यह विचार बहुत पसंद है। बुरे से अच्छे से बदलने के बारे में चिंता करने की ज़रूरत नहीं है - वास्तव में, मैं विशेष रूप से ऐसा परिवर्तन नहीं करना चाहता हूं। –

2

tblGoodItem और tblbadItem से छुटकारा पाएं और ItemType = "G" या "B" के साथ एक नई तालिका बनाएं और आइटम आईडी पर एक अनन्य अनुक्रमणिका या कुंजी डालें, तो tblItem पर कोई बाधा नहीं है।

+0

कोई नहीं कर सकता, मुझे डर है। अच्छी वस्तुओं में कुछ गुण होते हैं जिनके पास बुरी चीजें नहीं होती हैं, और इसके विपरीत। –

+0

यदि कुछ अंतर हैं, तो 10 अंतर या उससे कम के बाद, फिर भी मैं उन्हें गठबंधन करता हूं, उन्हें नल की अनुमति देता हूं और टाइप कॉलम –

1

आप कथन का उपयोग CHECK प्रतिबंध में नहीं कर सकते - वास्तव में यह नहीं कि वे वास्तव में क्या डिजाइन किए गए थे।

मुझे लगता है कि आपका सबसे अच्छा विकल्प आइटम आईडी में यूडीएफ पास लिखना होगा और जांचना होगा कि यह मौजूद है या नहीं। इस परिदृश्य के लिए यह वास्तव में सबसे आसान विकल्प है।

मैंने कुछ परीक्षण डेटा और एक उदाहरण समारोह जोड़ा है।

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 
+0

के आधार पर उन्हें जांचने के लिए चेक बाधा जोड़ता है, ऐसे यूडीएफ मल्टी-पंक्ति अपडेट के लिए सही तरीके से काम नहीं करते हैं –

+0

@AlexKuznetsov - क्या आप विस्तारित कर सकते हैं कि यह क्यों काम नहीं करेगा। मैंने एक परीक्षण बनाया है और यह ठीक काम करता है? – codingbadger

+0

मेरी माफ़ी, मैं गलत था। हालांकि, ऐसे यूडीएफ बहुत धीमे होते हैं, और यदि आप स्नैपशॉट अलगाव का उपयोग करते हैं तो आप समरूपता के तहत गलत परिणाम प्राप्त कर सकते हैं। –

1

मैं शायद यहां आपकी व्यावसायिक आवश्यकताओं को समझ नहीं रहा हूं लेकिन आप अच्छे और बुरे सामानों के लिए एक अलग टेबल क्यों चाहते हैं? क्या ये एक ही चीज़ के अवशोषण नहीं हैं?

आईबैडइटम ध्वज का उपयोग क्यों न करें या अधिक विशेष रूप से एक आइटम कंडीशनस्टैटस कॉलम का उपयोग न करें।

1

tblItem में, आइटम टाइप प्रकार जोड़ें। यह सुनिश्चित करने के लिए एक जांच बाधा है कि आइटम टाइप या तो अच्छा या बुरा है। (ItemID, itemType) पर एक अनूठी बाधा बनाएं

आइटम और टाइप करें दोनों खराब और अच्छी वस्तु तालिकाओं में टाइप करें। यह सुनिश्चित करने के लिए एक जांच बाधा है कि आइटम टाइप अच्छी तालिका में अच्छा है, और खराब तालिका में खराब है।

संबंधित मुद्दे

 संबंधित मुद्दे