8

से कोई फर्क नहीं पड़ता है, मुझे लगता है कि निम्न उदाहरण स्थिति को सबसे अच्छी तरह समझाएगा।विशिष्टता को कैसे कार्यान्वित करें जहां फ़ील्ड का क्रम

------------------------------------- 
Member1 int  NOT NULL (FK)(PK) 
Member2 int  NOT NULL (FK)(PK) 
------------------------------------- 
Statust char(1) NOT NULL 

यहाँ तालिका के लिए तालिका सामग्री हैं:: मान लीजिए कि हम निम्न तालिका संरचना है चलो

Member1 Member2 Status 
---------------------------- 
    100  105  A 

मेरा प्रश्न कैसे मैं विशिष्टता लागू करते है ताकि निम्न सम्मिलित बयान होगा असफल पहले से ही तालिका में उस एक पंक्ति के आधार पर।

INSERT status_table (Member1,Member2,Status) VALUES(105,100,'D'); 

असल में, मैं दो सदस्यों के बीच संबंध मॉडल करने की कोशिश कर रहा हूं। स्थिति फ़ील्ड वही है जो हमारे पास है (100,105) या (105,100)।

मुझे पता है कि मैं तालिका में सामग्री की जांच करने के लिए पहले_insert और first_update ट्रिगर का उपयोग कर सकता हूं। लेकिन मैं सोच रहा था कि क्या ऐसा करने का एक बेहतर तरीका था ... क्या मेरा डेटाबेस मॉडल अलग होना चाहिए ...

+0

क्यों न यू जांच बाधा का उपयोग यहां एक संपूर्ण स्क्रिप्ट दृष्टिकोण को दर्शाता है है आपके स्टेटस कॉलम पर? – Teja

+0

@ वेनक आप चेक बाधा के वाक्यविन्यास दिखा सकते हैं? –

+1

मुझे लगता है कि तालिका को अलग-अलग डिजाइन किया जाना चाहिए –

उत्तर

5

आप सुनिश्चित कर सकते हैं कि सभी आवेदनों/उपयोगकर्ताओं

ALTER TABLE Status_table 
    ADD CONSTRAINT Status_table_Prevent_double_pairs 
    CHECK (Member1 < Member2) 

आपको लगता है कि ऐसा करने के लिए नहीं करना चाहते हैं: सदस्यों की आईडी संगृहीत कम से कम करने के लिए सबसे बड़ी आदेश (Member1 में कम से कम MemberID और Member2 में सबसे बड़ी) में है, तो आप बस एक चेक बाधा जोड़ सकता है या आप उस अतिरिक्त जानकारी को संग्रहीत करना चाहते हैं (क्योंकि आप संग्रह कर रहे हैं (केवल एक उदाहरण) कि "सदस्य 100 आमंत्रित (पसंद, मार डाला, जो कुछ भी) सदस्य 150" और इसके विपरीत नहीं), तो आप @ तेगीरी के दृष्टिकोण का उपयोग कर सकते हैं, थोड़ा संशोधित कर सकते हैं (दो बड़े पर्याप्त पूर्णांक गुणा करना अन्यथा एक अतिप्रवाह समस्या होगी):

CREATE TABLE Status_table 
(Member1 INT NOT NULL 
, Member2 INT NOT NULL 
, Status CHAR(1) NOT NULL 
, MemberOne AS CASE WHEN Member1 < Member2 THEN Member1 ELSE Member2 END 
      --- a computed column 
, MemberTwo AS CASE WHEN Member1 < Member2 THEN Member2 ELSE Member1 END 
      --- and another one 
, PRIMARY KEY (Member1, Member2) 
, UNIQUE (MemberOne, MemberTwo) 
, ...         --- FOREIGN KEY details, etc 
) ; 
+0

यह जॉनडेवी के दृष्टिकोण से तुलना कैसे करता है। कौन सा सबसे अच्छा समाधान है? – Cristina

+0

मुझे यह बेहतर पसंद है क्योंकि यह चेकसम टकराव की संभावना के बारे में किसी भी धारणा पर भरोसा नहीं करता है। –

+1

दोनों प्राथमिक कुंजी और एक अद्वितीय इंडेक्स होने के बजाय, क्या मैं सिर्फ प्राथमिककी (सदस्यऑन, सदस्य दो) नहीं बना सकता और इसमें सभी मामलों को शामिल किया जाएगा? – Cristina

3

डेटाबेस मॉडल विफल रहता है क्योंकि आपके पास दो इकाइयां {सदस्य 1, सदस्य 2} हैं, जो कहती हैं कि यह नहीं करती कोई फर्क नहीं पड़ता कि कौन सा है, आप कह रहे हैं एक ही इकाई {सदस्य} हैं। दूसरे शब्दों में, आपके पास दो स्थानों पर एक तथ्य है, संबंधपरक डेटाबेस डिज़ाइन के मुख्य पापों में से एक।

रिश्ते की प्रकृति को बेहतर मॉडल करने के लिए एक उच्च स्तरीय समाधान होगा। एक उदाहरण दो व्यक्तियों का विवाह हो सकता है। "दुल्हन और दुल्हन विवाहित हैं" की बजाय और पहले जो सूचीबद्ध हो जाता है, उस पर झगड़ा करते हुए, आप "विवाह #xyz प्रतिभागियों ए और बी के बीच है"। तो, एक प्राथमिक कुंजी के साथ तालिका विवाह, विवाह के लिए विदेशी कुंजी के साथ मेज विवाहमेम्बर, "व्यक्ति" की विदेशी कुंजी, और दोनों स्तंभों पर प्राथमिक कुंजी। आइए आपके पास दो से अधिक सदस्य हैं, जो उपयोगी हो सकते हैं यदि आप हेनलेन की कहानी में हैं।

यदि आप मौजूदा स्कीमा के साथ फंस गए हैं (और हम सभी नहीं हैं), तो मुझे पहले सूचीबद्ध सबसे कम मूल्य के साथ डेटा प्रस्तुत करने की आवश्यकता होगी, ताकि उन्हें हमेशा सही तरीके से आदेश दिया जा सके। आप एक गणना कॉलम के रूप में दो कॉलम पर चेकसम के साथ चाल कर सकते हैं, लेकिन यह विशिष्टता की बिल्कुल गारंटी नहीं देगा। लेकिन और हां, दिन के अंत में आपका मॉडल आपके उद्देश्यों के लिए कठोर रूप से त्रुटिपूर्ण प्रतीत होता है।


अनुशेष

नीचे टिप्पणी के अनुसार, अगर आप सदस्यों को बताया कि किसी दिए गए सदस्य से संबंधित है मॉडल कर रहे हैं, तो आप एक स्थिति "सदस्य अन्य सदस्यों से संबंधित है" है। यहां, Member1 "मुख्य" सदस्य है, और Member2 एक अन्य सदस्य है जो "यह" सदस्य संबंधित है। (और यह दो सदस्य स्तंभों के बीच भेद की आवश्यकता है।) इस प्रकार, यदि कोई संबंध द्वि-दिशात्मक है, तो आपको "सदस्य ए सदस्य बी से संबंधित है" दोनों को कवर करने के लिए दो प्रविष्टियों की आवश्यकता होगी, और "सदस्य बी है सदस्य ए से संबंधित "। यह निश्चित रूप से {सदस्य 1, सदस्य 2} पर प्राथमिक कुंजी के साथ लागू किया जाएगा, क्योंकि स्थिति अप्रासंगिक प्रतीत होती है (केवल एक ही संबंध है, स्थिति के आधार पर एकाधिक नहीं)।

+0

समझाएं इस उत्तर के लिए धन्यवाद। वास्तव में, आप सही हैं। जो मैं मॉडल बनाने की कोशिश कर रहा हूं वह दो सदस्यों के बीच संबंध है। इससे कोई फर्क नहीं पड़ता कि यह (ए, बी) या (बी, ए) - रिश्ते की स्थिति समान है। लेकिन मैं आपके द्वारा सुझाए गए मॉडल को काफी समझ नहीं पा रहा हूं। असल में, मेरे पास एक सदस्य तालिका है जिसमें मेरे सभी सदस्य शामिल हैं और मेरे पास एक स्टेटस टेबल है जिसमें किसी भी दो सदस्यों के बीच स्थिति शामिल है। क्या आप मेरी टेबल पर आधारित अपने मॉडल को समझा सकते हैं। – Cristina

+0

"यह एक सदस्य टेबल containg सदस्यों है"। यह सवाल पूछता है: ** क्या सदस्य? ** [इकाई] क्या है जिसमें ऐसे उदाहरण हैं जहां प्रत्येक उदाहरण के सदस्यों का अपना सेट हो सकता है? इकाई का मॉडल करें (मेरे उदाहरण में, विवाह) और इसके सदस्यों (विवाह में प्रतिभागियों) को सूचीबद्ध करें। –

+0

मेरे पास दो टेबल हैं: सदस्य और स्थिति। सदस्य तालिका में मेरे सभी सदस्य होते हैं और स्थिति तालिका एक रिलेशनशिप टेबल होती है। यह सदस्य तालिका और सदस्य तालिका के बीच फिर से कई संबंधों को परिभाषित करता है। "एक सदस्य को एक या अधिक सदस्यों से जोड़ा जा सकता है"। यह अपने आप पर कई से अधिक रिश्ते हैं। डीबी दुनिया में इसका मॉडल कैसे करें। – Cristina

1

एक ट्रिगर से अलग मौजूदा अनन्य बाधा को बढ़ाने के बेहतर तरीके के बारे में नहीं सोच सकता। जैसे

CREATE TRIGGER dbo.StatusTable_PreventDualUniques 
ON dbo.status_table 
INSTEAD OF INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    IF EXISTS (
     SELECT 1 FROM inserted AS i 
     INNER JOIN dbo.status_table AS s 
     ON i.Member1 = s.Member1 AND i.Member2 = s.Member2 
     OR i.Member2 = s.Member1 AND i.Member1 = s.Member2 
    ) 
    BEGIN 
     RAISERROR('Duplicate detected', 11, 1); 
    END 
    ELSE 
    BEGIN 
     INSERT dbo.status_table(Member1, Member2, Status) 
      SELECT Member1, Member2, Status 
      FROM inserted; 
    END 
END 

अब मेरे सिर के शीर्ष से यह केवल सिंगल-पंक्ति प्रविष्टियों से संबंधित है।यदि आपको बहु-पंक्ति प्रविष्टियों को संभालने की आवश्यकता है, तो तर्क थोड़ा अधिक जटिल हो सकता है, क्योंकि आपको inserted और inserted और बेस तालिका दोनों के बीच डुप्लीकेट की जांच करने की आवश्यकता है। यह डिफ़ॉल्ट अलगाव स्तर पर उच्च समेकन को भी संभाल नहीं करता है (उदाहरण के लिए एक और लेनदेन चेक और सम्मिलन के बीच एक डुप्लिकेट पंक्ति डालता है)। लेकिन यह एक शुरुआत होनी चाहिए।

Member1 और Member2 पर एक अद्वितीय गणना स्तंभ की कोशिश (आप भी UPDATE के लिए एक की आवश्यकता होगी ...)

+0

एक ट्रिगर की तुलना में एक चेक बाधा बेहतर नहीं होगी ?: जांच (सदस्य 1 <सदस्य 2) ' –

+0

मुझे लगता है, लेकिन जब तक कि एप्लिकेशन और/या उपयोगकर्ता पहले सदस्य मान में प्रवेश नहीं करते हैं, तो आप सक्षम नहीं होंगे तालिका खाली होने पर भी '105, 100' डालें। –

+0

कौन सा दृष्टिकोण यहां वर्णित ट्रिगर दृष्टिकोण या यपरक्यूब द्वारा वर्णित दृष्टिकोण बेहतर है? – Cristina

2

एक तरह से एक ट्रिगर से बचने के लिए:

create table test (Member1 int not null, Member2 int not null, Status char(1) 
, bc as abs(binary_checksum(Member1))+abs(binary_checksum(Member2)) PERSISTED UNIQUE) 

INSERT INTO test values(123, 456, 'A'); --succeeds 
INSERT INTO test values(123, 789, 'B'); --succeeds 
INSERT INTO test values(456, 123, 'D'); --fails with the following error: 
--Msg 2627, Level 14, State 1, Line 1 
--Violation of UNIQUE KEY constraint 'UQ__test__3213B1084A8F946C'. Cannot insert duplicate key in object 'dbo.test' 
+0

क्यों 'abs'? क्या इससे झूठी सकारात्मक संभावनाओं में वृद्धि नहीं होगी? –

+0

@ फिलिपकेली - सं। पेट योग को दो चेकसमों की मूल एन्ट्रॉपी को संरक्षित करने की अनुमति देता है, क्योंकि जहां भी सकारात्मक चेकसम नकारात्मक होते हैं, वहां रकम की सीमा कम हो जाती है। –

1
यहाँ

"सममित से एक अंश "एसक्यूएल डिजाइन पैटर्न" पुस्तक में "फ़ंक्शन" प्रासंगिक हो सकते हैं।

बक्से

असली दुनिया में
table Boxes (
    length integer, 
    width integer, 
    height integer 
) 

बॉक्स आयाम, हालांकि, आम तौर पर किसी भी विशिष्ट क्रम में दिया नहीं कर रहे हैं की एक सूची डेटाबेस पर विचार करें। पसंद आयाम लंबाई, चौड़ाई, और ऊंचाई अनिवार्य रूप से मनमाना है। क्या होगा यदि हम अपने आयामों के अनुसार बक्से की पहचान करना चाहते हैं? उदाहरण के लिए, हम यह बताने में सक्षम होना चाहते हैं कि लंबाई = 1, चौड़ाई = 2, और ऊंचाई = 3 वाला बॉक्स वही बॉक्स है जो लम्बाई = 3, चौड़ाई = 1, और ऊंचाई = 2 है। इसके अलावा, एक अद्वितीय आयामी बाधा घोषित करने के बारे में कैसे? अधिक विशेष रूप से, हम किसी भी दो बक्से की अनुमति नहीं देंगे जिनमें समान आयाम हों।

एक विश्लेषणात्मक दिमाग में कोई समस्या नहीं होगी कि समस्या का दिल कॉलम ऑर्डरिंग है। लंबाई, चौड़ाई और ऊंचाई कॉलम के मानों को एक और वैध रिकॉर्ड बनाने के लिए इंटरचेंज किया जा सकता है! इसलिए, हम क्यों 3 छद्म कॉलम ऐसी है कि

A ≤ B ≤ C 

फिर परिचय नहीं है, ए, बी कहते हैं, और सी, ए, बी पर एक अद्वितीय बाधा, सी हमारी आवश्यकता को पूरा करना चाहिए! इसे एक फ़ंक्शन आधारित अद्वितीय इंडेक्स के रूप में कार्यान्वित किया जा सकता है, जब तक हम लंबाई, चौड़ाई, ऊंचाई के संदर्भ में ए, बी, सी विश्लेषणात्मक रूप से व्यक्त कर सकें। केक का टुकड़ा: ए लंबाई, चौड़ाई, ऊंचाई का सबसे बड़ा है; सी उनमें से कम से कम है, लेकिन हम बी कैसे व्यक्त करते हैं? खैर, जवाब लिखना आसान है

B = least (greatest (length,width), 
      greatest (width,height), 
      greatest (height,length)) 

हालांकि समझाना मुश्किल है।

सामान्य रूप से गणितीय परिप्रेक्ष्य, बहुत स्पष्ट करता है। घन समीकरण

पर विचार करें तो हम जानते हैं कि जड़ों x1, x2, तो x3, घन बहुपदीय कारक हो सकता है, है कि हम

दोनों समीकरणों हम व्यक्त शादी एक, ख, ग गुणांक तो जड़ों x1 के मामले में , x2, x3

चित्र 4.1: बहुपद y=(x-x1)(x-x2)(x-x3) के ग्राफ का एक आकार पूरी तरह से जड़ x1, x2, और x3 द्वारा परिभाषित किया गया है। उनका आदान-प्रदान कुछ भी प्रभावित नहीं करता है।

फ़ंक्शन -x1-x2-x3, x1x2+x2x3+x3x1, -x1x2x3 सममित हैं। X1, x2, x3 को अनुमति देना मानों पर कोई प्रभाव नहीं है ए, बी, सी। दूसरे शब्दों में, घन समीकरण की जड़ों के बीच क्रम अप्रासंगिक है: औपचारिक रूप से, हम जड़ों के एक सेट की बात करते हैं, न कि जड़ों की सूची 1। बॉक्सेस के साथ हमारे उदाहरण में यह वही प्रभाव है जिसे हम चाहते हैं।लंबाई, चौड़ाई, ऊंचाई के मामले में फिर से लिखा सममित कार्यों

length+width+height 
length*width+width*height+height*length 
length*width*height 

उन भाव तथ्य यह है कि एक सुडौल समारोह का निषेध भी सममित है का लाभ उठाकर एक छोटे से सरल बनाया गया है।

हमारा अंतिम समाधान पहले के समान ही है, जहां सबसे बड़ा ऑपरेटर गुणा की भूमिका निभाता है, जबकि कम से कम ऑपरेटर अतिरिक्त होता है। यह एक समाधान है, जो एक मिश्रण में दो

least(length,width,height) 
least(length+width,width+height,height+length) 
length+width+height 

के बीच एक पाठक की जांच कर सकते है कि इन तीन कार्यों फिर symmetric2 हैं सुझाने के लिए भी संभव है। अंतिम चरण औपचारिक एसक्यूएल में हमारे समाधान रिकॉर्डिंग है

table Boxes (
    length integer, 
    width integer, 
    height integer 
); 

create unique index b_idx on Boxes(
    length + width + height, 
    length * width + width * height + height * length, 
    length * width * height 
); 

सममित कार्यों एक गंधा समाधान के लिए एक आधार प्रदान करते हैं। अभ्यास में हालांकि, स्कीमा रीडिज़ाइन द्वारा अक्सर एक समस्या हल की जा सकती है। बॉक्स सूची डेटाबेस उदाहरण में, हम भी स्कीमा को नया स्वरूप की आवश्यकता नहीं है: और हम बस स्वेच्छापूर्ण रिकॉर्ड (length,width,height) डालने की प्रथा को बदलने के लिए आवश्यकता हो सकती है, मांग है कि

length ≥ width ≥ height 
0

तालिका को स्वयं इस विशेष व्यावसायिक तर्क को लागू करने की कोशिश करने के बजाय, क्या यह संग्रहीत प्रक्रिया में इसे समाहित करना बेहतर होगा? आप निश्चित रूप से दो सदस्यों के बीच अद्वितीय संबंधों को लागू करने में अधिक लचीलापन प्राप्त करते हैं।

+0

इसके साथ समस्या यह है कि आप सभी डेटा मैनिपुलेशन को संग्रहीत प्रक्रिया के माध्यम से लागू नहीं कर सकते हैं। आप कोशिश कर सकते हैं, लेकिन अधिकांश वास्तविक दुनिया परिदृश्य में यह एक गैर स्टार्टर है। –

2

यहां देखने का एक वैकल्पिक तरीका है। आप वास्तव में इस नियम को लागू कर सकते हैं कि पारस्परिक संबंध हमेशा दो पंक्तियों, (ए, बी) और (बी, ए) की उपस्थिति से व्यक्त किया जाता है, केवल एक के बजाय।

CREATE TABLE MutualRelationship 
(Member1 INT NOT NULL, 
    Member2 INT NOT NULL, 
    Status CHAR(1), 
PRIMARY KEY (Member1, Member2), 
UNIQUE (Member1, Member2, Status), 
FOREIGN KEY (Member2, Member1, Status) REFERENCES MutualRelationship (Member1, Member2, Status)); 

INSERT INTO MutualRelationship (Member1, Member2, Status) 
VALUES 
(100,105,'A'), 
(105,100,'A'); 
1

@ypercube's solution पर एक मामूली बदलाव एक अनुक्रमित दृश्य बनाते हैं और देखने के लिए अद्वितीय बाधा स्थानांतरित करने के लिए किया जाएगा।

/* the reference table (almost irrelevant for the tests, 
    but added to make the environment closer to the one in the question) */ 
CREATE TABLE dbo.Members (
    ID int IDENTITY CONSTRAINT PK_Members PRIMARY KEY, 
    Name varchar(50) 
); 

GO 

/* the table to add the constraint on */ 
CREATE TABLE dbo.Data (
    Member1 int CONSTRAINT FK_Data_Member1 FOREIGN KEY REFERENCES dbo.Members (ID), 
    Member2 int CONSTRAINT FK_Data_Member2 FOREIGN KEY REFERENCES dbo.Members (ID), 
    Statust char(1), 
    CONSTRAINT PK_Data PRIMARY KEY (Member1, Member2) 
); 

GO 

/* the indexed view that the constraint will actually be applied to */ 
CREATE VIEW dbo.DataView 
WITH SCHEMABINDING /* required with indexed views */ 
AS 
SELECT 
    /* the column definitions are practically identical to ypercube's */ 
    Member1 = CASE WHEN Member1 > Member2 THEN Member2 ELSE Member1 END, 
    Member2 = CASE WHEN Member1 > Member2 THEN Member1 ELSE Member2 END 
FROM dbo.Data 

GO 

/* finally, the constraint itself */ 
CREATE UNIQUE CLUSTERED INDEX UQ_DataView ON dbo.DataView (Member1, Member2); 

GO 

/* preparing the stage: adding some data to the reference table */ 
INSERT INTO dbo.Members (Name) 
SELECT 'Member A' UNION ALL 
SELECT 'Member B' UNION ALL 
SELECT 'Member C'; 

GO 

/* the first two rows should and do insert into the target table without issues */ 
INSERT INTO dbo.Data (Member1, Member2, Statust) VALUES (3, 1, 'A'); 
INSERT INTO dbo.Data (Member1, Member2, Statust) VALUES (2, 3, 'A'); 

GO 

/* and this one fails, which demonstrates the constraint in work */ 
INSERT INTO dbo.Data (Member1, Member2, Statust) VALUES (1, 3, 'B'); 

GO 

/* cleaning up */ 
DROP VIEW dbo.DataView; 
DROP TABLE dbo.Data; 
DROP TABLE dbo.Members; 

MSDN पर सूचीबद्ध विचारों के बारे में और अधिक पढ़ें::

+0

मुझे यह तथ्य पसंद है कि अतिरिक्त फ़ील्ड मेरी वास्तविक तालिका को प्रदूषित नहीं कर रहे हैं। दूसरी तरफ, यदि वह दृश्य मुझे बिना जानने के गिरा दिया जाता है तो मैं बाधा खो दूंगा। मुझे लगता है कि [@ ypercube का समाधान] (http://stackoverflow.com/a/9707552/297408) अधिक मूर्खतापूर्ण है। – Cristina

+0

उचित बिंदु। जब मैं इस समाधान की पेशकश कर रहा था, मुझे एहसास हुआ कि अतिरिक्त फ़ील्ड को अलग करने की संभावना @ ypercube की तुलना में इसका एकमात्र लाभ था, और बहुत ही सामग्री नहीं। मुझे यकीन है कि मैं कुछ परिदृश्यों में अनुक्रमित दृश्य दृष्टिकोण को प्राथमिकता दे सकता हूं, लेकिन शायद ज्यादातर मामलों में मैं तालिका में अतिरिक्त फ़ील्ड को उसी आधार पर सहन करना चुनूंगा जैसा कि आप चाहते हैं, यानि तालिका में रखी गई बाधा को बनाए रखने के पक्ष में भी। –

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