Database
 sql >> डेटाबेस >  >> RDS >> Database

पूर्ण जटिलताएं - भाग 4, मानक अद्वितीय बाधा गुम है

यह लेख NULL जटिलताओं के बारे में एक श्रृंखला में भाग 4 है। पिछले लेखों (भाग 1, भाग 2, और भाग 3) में, मैंने एक लापता मान के लिए एक मार्कर के रूप में NULL के अर्थ को कवर किया, तुलना में और अन्य क्वेरी तत्वों में NULL कैसे व्यवहार करते हैं, और मानक NULL हैंडलिंग सुविधाएँ जो नहीं हैं अभी तक टी-एसक्यूएल में उपलब्ध है। इस महीने मैं आईएसओ/आईईसी एसक्यूएल मानक में एक अद्वितीय बाधा को परिभाषित करने और टी-एसक्यूएल में काम करने के तरीके के बीच अंतर को कवर करता हूं। मैं अनुकूलित समाधान भी प्रदान करूंगा जिन्हें आप मानक कार्यक्षमता की आवश्यकता होने पर लागू कर सकते हैं।

मानक अद्वितीय बाधा

SQL सर्वर एक अद्वितीय बाधा को लागू करने के उद्देश्य से NULLs को गैर-NULL मानों की तरह ही संभालता है। अर्थात्, T पर एक अद्वितीय बाधा संतुष्ट होती है यदि और केवल तभी T की दो पंक्तियाँ R1 और R2 मौजूद न हों, जैसे कि R1 और R2 में अद्वितीय कॉलम में NULL और गैर-NULL मानों का समान संयोजन हो। उदाहरण के लिए, मान लीजिए कि आप col1 पर एक अद्वितीय बाधा को परिभाषित करते हैं, जो एक INT डेटाटाइप का एक पूर्ण स्तंभ है। तालिका को इस तरह से संशोधित करने का प्रयास जिसके परिणामस्वरूप col1 में NULL के साथ एक से अधिक पंक्तियाँ होंगी, उसे अस्वीकार कर दिया जाएगा, ठीक उसी तरह जैसे एक संशोधन जिसके परिणामस्वरूप col1 में मान 1 वाली एक से अधिक पंक्तियाँ अस्वीकृत हो जाएँगी।

मान लीजिए कि आप NULLable INT कॉलम col1 और col2 के संयोजन पर एक समग्र अद्वितीय बाधा परिभाषित करते हैं। तालिका को इस तरह से संशोधित करने का प्रयास जिसके परिणामस्वरूप (col1, col2) मानों के निम्नलिखित संयोजनों में से किसी एक की एक से अधिक घटनाएँ होंगी, को अस्वीकार कर दिया जाएगा:(NULL, NULL), (3, NULL), (NULL, 300) ), (1, 100)।

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

यदि आप किसी तालिका X पर कुछ तालिका Y को संदर्भित करते हुए एक विदेशी कुंजी को परिभाषित करना चाहते हैं, तो आपको निम्नलिखित विकल्पों में से एक के साथ संदर्भित कॉलम पर विशिष्टता लागू करनी होगी:

  • प्राथमिक कुंजी
  • अद्वितीय बाधा
  • गैर-फ़िल्टर्ड अद्वितीय अनुक्रमणिका

NULLable कॉलम पर प्राथमिक कुंजी की अनुमति नहीं है। दोनों एक अद्वितीय बाधा (जो कवर के नीचे एक सूचकांक बनाता है) और एक स्पष्ट रूप से बनाए गए अद्वितीय सूचकांक को NULLable कॉलम पर अनुमति दी जाती है, और उपरोक्त तर्क का उपयोग करके T-SQL में उनकी विशिष्टता को लागू करते हैं। संदर्भ तालिका को संदर्भित कॉलम में NULL के साथ पंक्तियाँ रखने की अनुमति है, भले ही संदर्भित तालिका में संदर्भित कॉलम में NULL के साथ एक पंक्ति हो। विचार एक वैकल्पिक संबंध का समर्थन करना है। संदर्भ तालिका में कुछ पंक्तियाँ ऐसी हो सकती हैं जो संदर्भित तालिका में किसी भी पंक्ति से संबंधित नहीं हैं। आप संदर्भ कॉलम में NULL का उपयोग करके इसे लागू करेंगे।

एक अद्वितीय बाधा के टी-एसक्यूएल कार्यान्वयन को प्रदर्शित करने के लिए, निम्न कोड चलाएँ, जो T3 नामक एक तालिका बनाता है जिसमें NULLable INT कॉलम col1 पर परिभाषित एक अद्वितीय बाधा है, और इसे कुछ नमूना पंक्तियों के साथ पॉप्युलेट करता है:

tempdb का उपयोग करें; यदि मौजूद है तो dbo.T3; GO क्रिएट टेबल dbo.T3 (col1 INT NULL, col2 INT NULL, CONSTRAINT UNQ_T3 UNIQUE (col1)); INSERT INTO dbo.T3(col1, col2) VALUES(1, 100),(2, -1),(NULL, -1),(3, 300);

तालिका को क्वेरी करने के लिए निम्न कोड का उपयोग करें:

चुनें* dbo.T3 से;

यह क्वेरी निम्न आउटपुट उत्पन्न करती है:

col1 col2--------------------------1 1002 -1NULL -13 300

col1 में NULL के साथ दूसरी पंक्ति डालने का प्रयास करें:

dbo.T3(col1, col2) VALUES(NULL, 400) में डालें;

यह प्रयास अस्वीकार कर दिया गया है और आपको निम्न त्रुटि मिलती है:

Msg 2627, Level 14, State 1
UNIQUE KEY बाधा 'UNQ_T3' का उल्लंघन। ऑब्जेक्ट 'dbo.T3' में डुप्लिकेट कुंजी सम्मिलित नहीं कर सकता। डुप्लिकेट कुंजी मान () है।

मानक अद्वितीय बाधा परिभाषा टी-एसक्यूएल संस्करण से थोड़ी अलग है। मुख्य अंतर NULL हैंडलिंग के साथ करना है। यहाँ मानक से अद्वितीय बाधा परिभाषा है:

<ब्लॉकक्वॉट>

"T पर एक अद्वितीय बाधा तभी संतुष्ट होती है जब T की दो पंक्तियाँ R1 और R2 मौजूद न हों, जैसे कि R1 और R2 के अद्वितीय कॉलम में समान गैर-NULL मान हों।"

तो, col1 पर एक अद्वितीय बाधा के साथ एक तालिका T, col1 में NULL के साथ कई पंक्तियों की अनुमति देगा, लेकिन col1 में समान गैर-नल मान वाली कई पंक्तियों को अस्वीकार कर देगा।

यह समझाने में थोड़ा मुश्किल है कि एक समग्र अद्वितीय बाधा के साथ मानक के अनुसार क्या होता है। कहें कि आपके पास (col1, col2) पर परिभाषित एक अद्वितीय बाधा है। आपके पास (NULL, NULL) के साथ कई पंक्तियाँ हो सकती हैं, लेकिन आपके पास (3, NULL) वाली कई पंक्तियाँ नहीं हो सकती हैं, ठीक उसी तरह जैसे आपके पास (1, 100) वाली कई पंक्तियाँ नहीं हो सकती हैं। इसी तरह, आपके पास (NULL, 300) वाली कई पंक्तियाँ नहीं हो सकतीं। मुद्दा यह है कि आपको अद्वितीय कॉलम में समान गैर-शून्य मानों वाली एकाधिक पंक्तियां रखने की अनुमति नहीं है। एक विदेशी कुंजी के लिए, आपके पास संदर्भ तालिका में किसी भी संख्या में पंक्तियाँ हो सकती हैं, सभी संदर्भ स्तंभों में NULLs के साथ, संदर्भित तालिका में मौजूद होने के बावजूद। ऐसी पंक्तियाँ संदर्भित तालिका (वैकल्पिक संबंध) में किसी भी पंक्ति से संबंधित नहीं हैं। हालांकि, यदि आपके पास किसी भी संदर्भ कॉलम में कोई गैर-शून्य मान है, तो संदर्भित तालिका में संदर्भित कॉलम में समान गैर-शून्य मानों के साथ एक पंक्ति मौजूद होनी चाहिए।

मान लीजिए कि आपके पास प्लेटफ़ॉर्म में एक डेटाबेस है जो मानक अद्वितीय बाधा का समर्थन करता है और आपको उस डेटाबेस को SQL सर्वर पर माइग्रेट करने की आवश्यकता है। यदि अद्वितीय कॉलम NULLs का समर्थन करते हैं, तो आपको SQL सर्वर में अनन्य बाधाओं के प्रवर्तन के साथ समस्याओं का सामना करना पड़ सकता है। स्रोत सिस्टम में मान्य माना गया डेटा SQL सर्वर में अमान्य माना जा सकता है। निम्नलिखित अनुभागों में मैं SQL सर्वर में कई संभावित समाधान तलाशूंगा।

समाधान 1, फ़िल्टर किए गए अनुक्रमणिका या अनुक्रमित दृश्य का उपयोग करके

मानक अद्वितीय बाधा कार्यक्षमता को लागू करने के लिए टी-एसक्यूएल में एक सामान्य कामकाज जब केवल एक लक्ष्य कॉलम शामिल होता है तो एक अद्वितीय फ़िल्टर्ड इंडेक्स का उपयोग करना होता है जो केवल उन पंक्तियों को फ़िल्टर करता है जहां लक्ष्य कॉलम न्यूल नहीं होता है। निम्नलिखित कोड T3 से मौजूदा अद्वितीय बाधा को हटाता है और इस तरह के सूचकांक को लागू करता है:

वैकल्पिक तालिका dbo.T3 ड्रॉप बाधा UNQ_T3; dbo.T3(col1) पर अद्वितीय गैर-अनुक्रमित अनुक्रमणिका idx_col1_notnull बनाएं जहां col1 पूर्ण नहीं है;

चूंकि अनुक्रमणिका केवल उन पंक्तियों को फ़िल्टर करती है जहाँ col1 NULL नहीं है, इसकी UNIQUE संपत्ति केवल गैर-NULL col1 मानों पर लागू होती है।

याद रखें कि T3 में पहले से ही col1 में NULL के साथ एक पंक्ति है। इस समाधान का परीक्षण करने के लिए, col1 में NULL के साथ दूसरी पंक्ति जोड़ने के लिए निम्न कोड का उपयोग करें:

dbo.T3(col1, col2) VALUES(NULL, 400) में डालें;

यह कोड सफलतापूर्वक चलता है।

याद रखें कि T3 में पहले से ही col1 में मान 1 के साथ एक पंक्ति है। col1 में 1 के साथ दूसरी पंक्ति जोड़ने का प्रयास करने के लिए निम्न कोड चलाएँ:

dbo.T3(col1, col2) VALUES(1, 500) में डालें;

जैसा अपेक्षित था, यह प्रयास निम्न त्रुटि के साथ विफल हो जाता है:

संदेश 2601, स्तर 14, राज्य 1
ऑब्जेक्ट 'dbo.T3' में अद्वितीय अनुक्रमणिका 'idx_col1_notnull' के साथ डुप्लीकेट कुंजी पंक्ति सम्मिलित नहीं कर सकता। डुप्लिकेट कुंजी मान (1) है।

T3 को क्वेरी करने के लिए निम्न कोड का उपयोग करें:

चुनें* dbo.T3 से;

यह कोड col1 में NULL के साथ दो पंक्तियों को दिखाते हुए निम्न आउटपुट उत्पन्न करता है:

col1 col2--------------------------1 1002 -1NULL -13 300NULL 400

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

विदेशी कुंजी के साथ समस्या यह है कि SQL सर्वर को प्राथमिक कुंजी या एक अद्वितीय बाधा या संदर्भित कॉलम पर परिभाषित एक अद्वितीय गैर-फ़िल्टर किए गए अनुक्रमणिका की आवश्यकता होती है। यह तब काम नहीं करता जब संदर्भित कॉलम पर केवल एक अद्वितीय फ़िल्टर्ड इंडेक्स परिभाषित किया गया हो। आइए T3.col1 को संदर्भित करने वाली एक विदेशी कुंजी के साथ एक तालिका बनाने का प्रयास करें। तालिका T3 बनाने के लिए सबसे पहले निम्न कोड का उपयोग करें:

ड्रॉप टेबल अगर मौजूद है dbo.T3FK;गो क्रिएट टेबल dbo.T3FK (आईडी नॉट नॉट न्यूल आइडेंटिटी कंस्ट्रेंट PK_T3FK प्राइमरी की, col1 INT NULL, col2 INT NULL, othercol VARCHAR(10) NOT NULL);

फिर T3FK.col1 से T3.col1 की ओर इशारा करते हुए एक विदेशी कुंजी जोड़ने के प्रयास में निम्न कोड चलाने का प्रयास करें:

ALTER TABLE dbo.T3FK ADD CONSTRAINT FK_T3_T3FK विदेशी कुंजी(col1) संदर्भ dbo.T3(col1);

यह प्रयास निम्न त्रुटि के साथ विफल होता है:

संदेश 1776, स्तर 16, राज्य 0
संदर्भित तालिका 'dbo.T3' में कोई प्राथमिक या उम्मीदवार कुंजी नहीं है जो विदेशी कुंजी 'FK_T3_T3FK' में संदर्भ स्तंभ सूची से मेल खाती है।

संदेश 1750, स्तर 16, राज्य 1
बाधा या सूचकांक नहीं बना सका। पिछली त्रुटियां देखें।

इस बिंदु पर, मौजूदा फ़िल्टर किए गए इंडेक्स को क्लीनअप के लिए छोड़ दें:

DROP INDEX idx_col1_notnull ON dbo.T3;

तालिका T3FK को न छोड़ें, क्योंकि आप इसे बाद के उदाहरणों में उपयोग करेंगे।

फ़िल्टर किए गए इंडेक्स समाधान के साथ दूसरी समस्या, यह मानते हुए कि आपको विदेशी कुंजी की आवश्यकता नहीं है, यह तब काम नहीं करता है जब आपको कई स्तंभों पर मानक अद्वितीय बाधा कार्यक्षमता को लागू करने की आवश्यकता होती है, उदाहरण के लिए संयोजन (col1, col2) पर . याद रखें कि मानक अद्वितीय बाधा अद्वितीय कॉलम में मूल्यों के डुप्लिकेट गैर-नल संयोजनों को अस्वीकार करती है। फ़िल्टर किए गए इंडेक्स के साथ इस तर्क को लागू करने के लिए, आपको केवल उन पंक्तियों को फ़िल्टर करने की आवश्यकता है जहां कोई भी अद्वितीय कॉलम न्यूल नहीं है। अलग-अलग तरीके से, आपको केवल उन पंक्तियों को फ़िल्टर करने की आवश्यकता है जिनमें सभी अद्वितीय स्तंभों में NULL नहीं हैं। दुर्भाग्य से, फ़िल्टर किए गए इंडेक्स केवल बहुत ही सरल अभिव्यक्तियों की अनुमति देते हैं। वे कॉलम पर OR, NOT या हेरफेर का समर्थन नहीं करते हैं। इसलिए निम्न में से कोई भी अनुक्रमणिका परिभाषा वर्तमान में समर्थित नहीं है:

Dbo.T3(col1, col2) पर UNNCLUSTERED INDEX idx_customunique बनाएं जहां col1 NULL नहीं है या col2 NULL नहीं है; dbo.T3 (col1, col2) पर अद्वितीय गैर-अनुक्रमित अनुक्रमणिका idx_customunique बनाएं जहां नहीं (col1 शून्य है और col2 पूर्ण है); dbo.T3(col1, col2) पर UNNCLUSTERED INDEX idx_customunique बनाएं जहां COALESCE(col1, col2) NULL नहीं है;

ऐसे मामले में वर्कअराउंड एक क्वेरी के आधार पर एक अनुक्रमित दृश्य बनाना है जो ऊपर दिए गए WHERE क्लॉज में से एक के साथ T3 से col1 और col2 लौटाता है, एक अद्वितीय क्लस्टर इंडेक्स (col1, col2) के साथ, जैसे:

क्रिएट व्यू dbo.T3CustomUnique के साथ SCHEMABINDINGAS सेलेक्ट col1, col2 dbo.T3 से जहां col1 न्यूल नहीं है या col2 न्यूल नहीं है, GO UNIQUE CLUSTERED INDEX क्रिएट करें idx_col1_col2 ON dbo. 

आपको (col1, col2) में (NULL, NULL) के साथ कई पंक्तियों को जोड़ने की अनुमति होगी, लेकिन आपको (col1, col2), जैसे कि (col1, col2) में मानों के गैर-नल संयोजनों की कई बारंबारता जोड़ने की अनुमति नहीं होगी। , NULL) या (NULL, 300) या (1, 100)। फिर भी, यह समाधान किसी विदेशी कुंजी का समर्थन नहीं करता है।

इस समय, सफाई के लिए निम्न कोड चलाएँ:

ड्रॉप व्यू अगर मौजूद है dbo.T3CustomUnique;

समाधान 2, सरोगेट कुंजी और परिकलित कॉलम का उपयोग करके

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

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

ALTER TABLE dbo.T3 आईडी जोड़ें, पूरी तरह से पहचान न होने पर, केस के रूप में फ़्लैग करें जब col1 पूरी तरह से तब आईडी हो अन्यथा 0 END पर्सिस्टेड, CONSTRAINT UNQ_T3_col1_flag UNIQUE(col1, फ़्लैग);

T3 को क्वेरी करने के लिए निम्न कोड का उपयोग करें:

चुनें* dbo.T3 से;

यह कोड निम्न आउटपुट उत्पन्न करता है:

col1 col2 id फ्लैग-------------------------------------------------- -1 100 1 02 -1 2 0NULL -1 3 33 300 4 0NULL 400 5 5

संदर्भ तालिका (हमारे मामले में T3FK) के लिए, आप एक परिकलित कॉलम जोड़ते हैं जिसे ध्वज कहा जाता है जो हमेशा 0 पर सेट होता है, और एक विदेशी कुंजी (col1, ध्वज) पर परिभाषित होती है जो T3 के अद्वितीय कॉलम (col1, ध्वज) की ओर इशारा करती है, जैसे :

ALTER TABLE dbo.T3FK ADD फ्लैग as 0 PERSISTED, CONSTRAINT FK_T3_T3FK FOREIGN KEY(col1, फ्लैग) संदर्भ dbo.T3(col1, flag);

आइए इस समाधान का परीक्षण करें।

निम्नलिखित पंक्तियों को जोड़ने का प्रयास करें:

dbo.T3FK(col1, col2, othercol) VALUES (1, 100, 'A'), (2, -1, 'B'), (3, 300, 'C');

इन पंक्तियों को सफलतापूर्वक जोड़ दिया गया है, जैसा कि उन्हें होना चाहिए, क्योंकि सभी में संबंधित संदर्भित पंक्तियाँ हैं।

तालिका T3FK को क्वेरी करें:

चुनें * dbo.T3FK से;

आपको निम्न आउटपुट मिलता है:

आईडी col1 col2 अन्यकॉल फ्लैग ---------------------------------------------- ------------1 1 100 ए 02 2 -1 बी 03 3 300 सी 0

ऐसी पंक्ति जोड़ने का प्रयास करें जिसमें संदर्भित तालिका में कोई संगत पंक्ति न हो:

dbo.T3FK(col1, col2, othercol) VALUES (4, 400, 'D') में डालें;

प्रयास को अस्वीकार कर दिया गया है, जैसा कि निम्न त्रुटि के साथ होना चाहिए:

संदेश 547, स्तर 16, राज्य 0
INSERT कथन विदेशी कुंजी बाधा "FK_T3_T3FK" के विपरीत है। डेटाबेस "TSQLV5", तालिका "dbo.T3" में संघर्ष हुआ।

col1 में NULL के साथ T3FK में एक पंक्ति जोड़ने का प्रयास करें:

dbo.T3FK(col1, col2, othercol) VALUES (NULL, NULL, 'E') में डालें;

इस पंक्ति को T3FK (वैकल्पिक संबंध) में किसी भी पंक्ति से संबंधित नहीं माना जाता है और, मानक के अनुसार, col1 में संदर्भित तालिका में NULL मौजूद है या नहीं, इसकी अनुमति दी जानी चाहिए। टी-एसक्यूएल इस परिदृश्य का समर्थन करता है, और पंक्ति सफलतापूर्वक जोड़ दी जाती है।

तालिका T3FK को क्वेरी करें:

चुनें * dbo.T3FK से;

यह कोड निम्न आउटपुट उत्पन्न करता है:

आईडी col1 col2 अन्यकॉल फ्लैग ---------------------------------------------- ------------1 1 100 ए 02 2 -1 बी 03 3 300 सी 05 न्यूल न्यूल ई 0

जब आपको किसी एकल स्तंभ पर मानक विशिष्टता कार्यक्षमता को लागू करने की आवश्यकता होती है तो समाधान अच्छी तरह से काम करता है। लेकिन यह एक समस्या है जब आपको कई स्तंभों पर विशिष्टता लागू करने की आवश्यकता होती है। समस्या को प्रदर्शित करने के लिए, पहले T3 और T3FK तालिकाएँ छोड़ें:

ड्रॉप टेबल अगर मौजूद है dbo.T3FK, dbo.T3;

(col1, col2, ध्वज) पर एक समग्र अद्वितीय बाधा के साथ T3 को फिर से बनाने के लिए निम्न कोड का उपयोग करें:

टेबल dbo.T3 बनाएं (col1 INT NULL, col2 INT NULL, id INT NOT NULL IDENTITY, जब col1 NULL हो और col2 NULL हो तो id ELSE 0 END परसिस्टेड, CONSTRAINT UNQ_T3 UNIQUE(col1, col2, फ्लैग करें) ));

ध्यान दें कि जब col1 और col2 दोनों NULLs हों और अन्यथा 0 हों, तो फ़्लैग को id पर सेट किया जाता है।

अद्वितीय बाधा ही अच्छी तरह से काम करती है।

T3 में कुछ पंक्तियों को जोड़ने के लिए निम्नलिखित कोड चलाएँ, जिसमें (नल, न्यूल) (col1, col2) की कई आवृत्तियाँ शामिल हैं:

dbo.T3(col1, col2) VALUES(1, 100),(1, 200),(NULL, NULL),(NULL, NULL) में डालें;

इन पंक्तियों को सफलतापूर्वक जोड़ दिया गया है जैसा उन्हें करना चाहिए।

(col1, col2) में (1, NULL) की दो घटनाओं को जोड़ने का प्रयास करें:

dbo.T3(col1, col2) VALUES(1, NULL),(1, NULL) में डालें;

यह प्रयास विफल रहता है जैसा कि निम्न त्रुटि के साथ होना चाहिए:

Msg 2627, Level 14, State 1
UNIQUE KEY बाधा 'UNQ_T3' का उल्लंघन। ऑब्जेक्ट 'dbo.T3' में डुप्लिकेट कुंजी सम्मिलित नहीं कर सकता। डुप्लिकेट कुंजी मान (1, , 0) है।

(col1, col2) में (NULL, 100) की दो घटनाओं को जोड़ने का प्रयास करें:

dbo.T3(col1, col2) VALUES(NULL, 100),(NULL, 100) में डालें;

यह प्रयास भी विफल रहता है जैसा कि निम्न त्रुटि के साथ होना चाहिए:

Msg 2627, Level 14, State 1
UNIQUE KEY बाधा 'UNQ_T3' का उल्लंघन। ऑब्जेक्ट 'dbo.T3' में डुप्लिकेट कुंजी सम्मिलित नहीं कर सकता। डुप्लीकेट कुंजी मान (, 100, 0) है।

निम्नलिखित दो पंक्तियों को जोड़ने का प्रयास करें, जहां कोई उल्लंघन नहीं होना चाहिए:

dbo.T3(col1, col2) VALUES(3, NULL),(NULL, 300) में डालें;

इन पंक्तियों को सफलतापूर्वक जोड़ दिया गया है।

इस बिंदु पर तालिका T3 को क्वेरी करें:

चुनें* dbo.T3 से;

आपको निम्न आउटपुट मिलता है:

col1 col2 id फ्लैग-------------------------------------------------- -1 100 1 01 200 2 0 NULL 3 3 NULL NULL 4 43 NULL 9 0NULL 300 10 0

अब तक बहुत अच्छा।

इसके बाद, T3 के अद्वितीय कॉलम को संदर्भित करने वाली समग्र विदेशी कुंजी के साथ तालिका T3FK बनाने के लिए निम्न कोड चलाएँ:

टेबल डीबीओ.टी3एफके बनाएं(आईडी नॉट न्यूल आइडेंटिटी कंस्ट्रेंट पीके_टी3एफके प्राइमरी की, कोल1 इंट न्यूल, कोल2 इंट न्यूल, अन्य कॉल वर्चर(10) नॉट न्यूल, फ्लैग एएस 0 पर्सिस्टेड, कॉन्स्ट्रेंट एफके_टी3_टी3एफके फॉरेनकॉल 2, फ्लैग करें। ) संदर्भ dbo.T3(col1, col2, ध्वज));

यह समाधान स्वाभाविक रूप से (col1, col2) में (NULL, NULL) के साथ T3FK में पंक्तियों को जोड़ने की अनुमति देता है। समस्या यह है कि यह पंक्तियों को या तो col1 या col2 में जोड़ने की अनुमति देता है, भले ही अन्य कॉलम न्यूल न हो, और संदर्भित तालिका T3 में ऐसा कोई कुंजी संयोजन न हो। उदाहरण के लिए, निम्न पंक्ति को T3FK में जोड़ने का प्रयास करें:

dbo.T3FK(col1, col2, othercol) VALUES(5, NULL, 'A');
में INSERT करें

यह पंक्ति सफलतापूर्वक जोड़ दी गई है, भले ही T3 में कोई संबंधित पंक्ति न हो। मानक के अनुसार, इस पंक्ति की अनुमति नहीं दी जानी चाहिए।

ड्रॉइंग बोर्ड पर वापस...

समाधान 3, सरोगेट कुंजी और परिकलित कॉलम का उपयोग करके

पिछले समाधान (समाधान 2) के साथ समस्या तब उत्पन्न होती है जब आपको समग्र विदेशी कुंजी का समर्थन करने की आवश्यकता होती है। यह संदर्भ तालिका में पंक्तियों की अनुमति देता है जिसमें सूची में एक संदर्भ कॉलम में एक NULL होता है, भले ही अन्य संदर्भ कॉलम में गैर-नल मान हों, और संदर्भित तालिका में कोई संबंधित पंक्ति न हो। इसका समाधान करने के लिए, आप पिछले समाधान की विविधता का उपयोग कर सकते हैं, जिसे हम समाधान 3 कहेंगे।

पहले, मौजूदा तालिकाओं को छोड़ने के लिए निम्न कोड का उपयोग करें:

ड्रॉप टेबल अगर मौजूद है dbo.T3FK, dbo.T3;

संदर्भित तालिका में नए समाधान में (हमारे मामले में टी 3), आप अभी भी पहचान-आधारित आईडी सरोगेट कुंजी कॉलम का उपयोग करते हैं। आप अनकपथ नामक एक स्थायी गणना वाले कॉलम का भी उपयोग करते हैं। जब सभी अद्वितीय कॉलम (हमारे उदाहरण में col1 और col2) NULL होते हैं, तो आप unqpath को id (कोई विभाजक नहीं के एक वर्ण स्ट्रिंग प्रतिनिधित्व के लिए सेट करते हैं। ) जब कोई भी अद्वितीय कॉलम न्यूल नहीं होता है, तो आप CONCAT फ़ंक्शन का उपयोग करके अद्वितीय कॉलम मानों की एक अलग सूची के वर्ण स्ट्रिंग प्रतिनिधित्व के लिए unqpath सेट करते हैं। यह फ़ंक्शन एक खाली स्ट्रिंग के साथ NULL को प्रतिस्थापित करता है। एक विभाजक का उपयोग करना सुनिश्चित करना महत्वपूर्ण है जो सामान्य रूप से डेटा में ही प्रकट नहीं हो सकता है। उदाहरण के लिए, पूर्णांक col1 और col2 मानों के साथ आपके पास केवल अंक होते हैं, इसलिए अंक के अलावा कोई भी विभाजक काम करेगा। मेरे उदाहरण में मैं एक बिंदु (।) का उपयोग करूंगा। फिर आप unqpath पर एक अद्वितीय बाधा लागू करते हैं। जब सभी अद्वितीय कॉलम NULL (आईडी पर सेट) बनाम जब कोई भी अद्वितीय कॉलम NULL नहीं होता है, तो आपके पास कभी भी unqpath मान के बीच कोई विरोध नहीं होगा क्योंकि पूर्व मामले में unqpath में विभाजक नहीं होता है, और बाद के मामले में यह करता है . याद रखें कि आप समाधान 3 का उपयोग तब करेंगे जब आपके पास एक समग्र कुंजी केस होगा, और संभवतः समाधान 2 को प्राथमिकता दें, जो कि सरल है, जब आपके पास एकल कॉलम कुंजी केस हो। यदि आप समाधान 3 का उपयोग एकल-स्तंभ कुंजी के साथ भी करना चाहते हैं न कि समाधान 2 के साथ, तो सुनिश्चित करें कि आप विभाजक जोड़ते हैं जब अद्वितीय कॉलम NULL नहीं है, भले ही इसमें केवल एक मान शामिल हो। इस तरह से आपको कोई विरोध नहीं होगा जब एक पंक्ति में id जहां col1 NULL है, दूसरी पंक्ति में col1 के बराबर है, क्योंकि पूर्व में कोई विभाजक नहीं होगा और बाद वाला होगा।

यहाँ उपरोक्त जोड़ के साथ T3 बनाने के लिए कोड दिया गया है:

तालिका dbo.T3 बनाएं(col1 INT NULL, col2 INT NULL, id INT NOT NULL Identity, unqpath as case जब col1 NULL है और col2 NULL है तो कास्ट (id AS VARCHAR(10)) ELSE CONCAT(CAST(col1) AS VARCHAR(11)), '.', CAST(col2 AS VARCHAR(11))) END PERSISTED, CONSTRAINT UNQ_T3 UNIQUE(unqpath));

विदेशी कुंजी और संदर्भ तालिका से निपटने से पहले, आइए अद्वितीय बाधा का परीक्षण करें। याद रखें, यह अद्वितीय कॉलम में गैर-नल मानों के डुप्लिकेट संयोजनों को अस्वीकार करने वाला है, लेकिन यह अद्वितीय कॉलम में सभी-NULL की कई बारंबारता की अनुमति देता है।

कुछ पंक्तियों को जोड़ने के लिए निम्नलिखित कोड चलाएँ, जिसमें (NULL, NULL) की दो आवृत्तियाँ (col1, col2) शामिल हैं:

dbo.T3(col1, col2) VALUES(1, 100),(1, 200),(NULL, NULL),(NULL, NULL) में डालें;

यह कोड सफलतापूर्वक पूरा होता है जैसा इसे करना चाहिए।

(col1, col2) में (1, NULL) की दो घटनाओं को जोड़ने का प्रयास करें:

dbo.T3(col1, col2) VALUES(1, NULL),(1, NULL) में डालें;

यह कोड निम्न त्रुटि के साथ विफल रहता है जैसा कि इसे करना चाहिए:

Msg 2627, Level 14, State 1
UNIQUE KEY बाधा 'UNQ_T3' का उल्लंघन। ऑब्जेक्ट 'dbo.T3' में डुप्लिकेट कुंजी सम्मिलित नहीं कर सकता। डुप्लिकेट कुंजी मान (1.) है।

इसी तरह, निम्न प्रयास भी अस्वीकार कर दिया गया है:

dbo.T3(col1, col2) VALUES(NULL, 100),(NULL, 100) में डालें;

आपको निम्न त्रुटि मिलती है:

Msg 2627, Level 14, State 1
UNIQUE KEY बाधा 'UNQ_T3' का उल्लंघन। ऑब्जेक्ट 'dbo.T3' में डुप्लिकेट कुंजी सम्मिलित नहीं कर सकता। डुप्लिकेट कुंजी मान (.100) है।

कुछ और पंक्तियाँ जोड़ने के लिए निम्न कोड चलाएँ:

dbo.T3(col1, col2) VALUES(3, NULL),(NULL, 300) में डालें;

यह कोड सफलतापूर्वक चलता है जैसा इसे करना चाहिए।

इस बिंदु पर, क्वेरी T3:

चुनें* dbo.T3 से;

आपको निम्न आउटपुट मिलता है:

col1 col2 id unqpath-------------------------------------------------- -------------1 100 1 1.1001 200 2 1.200 NULL 3 3NULL NULL 4 43 NULL 9 3.NULL 300 10 .300

unqpath मानों का निरीक्षण करें और सुनिश्चित करें कि आप उनके निर्माण के पीछे के तर्क को समझते हैं, और ऐसे मामले के बीच का अंतर जहां सभी अद्वितीय कॉलम NULL (कोई विभाजक नहीं) हैं बनाम जब कम से कम एक NULL नहीं है (विभाजक मौजूद है)।

संदर्भ तालिका के लिए, T3FK; आप एक परिकलित कॉलम को भी परिभाषित करते हैं जिसे unqpath कहा जाता है, लेकिन उस स्थिति में जहां सभी संदर्भित कॉलम NULL हैं, आप कॉलम को NULL पर सेट करते हैं - आईडी पर नहीं। जब कोई भी रेफरेंसिंग कॉलम न्यूल नहीं होता है, तो आप उसी तरह से अलग किए गए मानों की सूची बनाते हैं जैसे आपने T3 में किया था। फिर आप T3FK.unqpath पर T3.unqpath की ओर इशारा करते हुए एक विदेशी कुंजी को परिभाषित करते हैं, जैसे:

 टेबल dbo.T3FK बनाएं (आईडी नॉट न्यूल आइडेंटिटी कंस्ट्रेंट PK_T3FK प्राइमरी की, col1 INT NULL, col2 INT NULL, अन्यकॉल VARCHAR(10) नॉट न्यूल, अनकपाथ ऐस केस जब col1 न्यूल है और col2 न्यूल कनेक्ट है (CAST(col1 AS VARCHAR(11)), '.', CAST(col2 AS VARCHAR(11))) END PersISTED, CONSTRAINT FK_T3_T3FK FOREIGN KEY(unqpath) संदर्भ dbo.T3(unqpath));

यह विदेशी कुंजी T3FK में पंक्तियों को अस्वीकार कर देगी जहां कोई भी संदर्भ स्तंभ NULL नहीं है, और संदर्भित तालिका T3 में कोई संबंधित पंक्ति नहीं है, जैसा कि निम्न प्रयास दिखाता है:

dbo.T3FK(col1, col2, othercol) VALUES(5, NULL, 'A');
में INSERT करें

यह कोड निम्न त्रुटि उत्पन्न करता है:

संदेश 547, स्तर 16, राज्य 0
INSERT कथन विदेशी कुंजी बाधा "FK_T3_T3FK" के विपरीत है। डेटाबेस "TSQLV5", तालिका "dbo.T3", कॉलम 'unqpath' में संघर्ष हुआ।

यह समाधान T3FK में पंक्तियाँ देगा जहाँ कोई भी संदर्भ स्तंभ तब तक NULL नहीं है जब तक T3 में संबंधित पंक्ति मौजूद है, साथ ही सभी संदर्भ स्तंभों में NULLs वाली पंक्तियाँ, क्योंकि ऐसी पंक्तियों को T3 में किसी भी पंक्ति से असंबंधित माना जाता है। निम्न कोड ऐसी मान्य पंक्तियों को T3FK में जोड़ता है:

dbo.T3FK(col1, col2, othercol) VALUES (1 , 100 , 'A'), (1 , 200 , 'B'), (3 , NULL, 'C'), (NULL, 300) में INSERT करें। , 'D'), (NULL, NULL, 'E'), (NULL, NULL, 'F');

यह कोड सफलतापूर्वक पूरा होता है।

T3FK को क्वेरी करने के लिए निम्न कोड चलाएँ:

चुनें * dbo.T3FK से;

आपको निम्न आउटपुट मिलता है:

आईडी col1 col2 Othercol unqpath-------------------------------------------------- --------------------------- 1 100 ए 1.1003 1 200 बी 1.2004 3 न्यूल सी 3.5 न्यूल 300 डी .3006 न्यूल न्यूल ई न्यूल7 न्यूल न्यूल एफ न्यूल 

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

निष्कर्ष

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 9 सबसे आम डेटाबेस डिज़ाइन त्रुटियाँ

  2. RDBMS और NoSQL को पाटना:2DX UI क्लस्टर का परिचय

  3. डेटाबेस के लिए डिस्क स्थान की योजना

  4. 19 डेटाबेस डिजाइन त्रुटियों के बारे में सीखने के लिए ऑनलाइन संसाधन

  5. ऑप्टिमाइज़ेशन थ्रेशोल्ड - डेटा को समूहीकृत और एकत्र करना, भाग 4