एक UNIQUE बाधा केवल एक NULL की अनुमति क्यों देती है?


36

तकनीकी रूप से, NULL = NULL गलत है, उस तर्क से कोई NULL किसी भी NULL के बराबर नहीं है और सभी NULL अलग हैं। इस का अर्थ यह नहीं है कि सभी NULLs अद्वितीय हैं और एक अद्वितीय सूचकांक NULLs की किसी भी संख्या को अनुमति देना चाहिए?


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
पॉल व्हाइट GoFundMonica कहते

जवाबों:


52

यह इस तरह से काम क्यों करता है? क्योंकि जिस तरह से वापस, किसी ने बिना किसी डिजाइन या निर्णय के परवाह किए कि मानक क्या कहता है (आखिरकार, हमारे पास NULLएस के साथ सभी प्रकार के अजीब व्यवहार हैं , और इच्छा पर अलग व्यवहार कर सकते हैं)। यही कारण है कि निर्णय तय करती है कि, में इस मामले NULL = NULL

यह एक बहुत ही स्मार्ट निर्णय नहीं था। उन्हें जो करना चाहिए था वह एएनएसआई मानक का पालन करने के लिए डिफ़ॉल्ट व्यवहार है, और यदि वे वास्तव में इस अजीब व्यवहार को चाहते हैं, तो इसे डीडीएल विकल्प जैसे WITH CONSIDER_NULLS_EQUALया के माध्यम से अनुमति दें WITH ALLOW_ONLY_ONE_NULL

निश्चित रूप से, 20/20 की बाधा है।

और हमारे पास एक वर्कअराउंड है, अब, वैसे भी, भले ही यह सबसे साफ या सबसे सहज न हो।

आप SQL Server 2008 और इसके बाद के संस्करण में एक अद्वितीय, फ़िल्टर किए गए अनुक्रमणिका बनाकर उचित ANSI व्यवहार प्राप्त कर सकते हैं।

CREATE UNIQUE INDEX foo ON dbo.bar(key) WHERE key IS NOT NULL;

यह एक से अधिक NULLमूल्य की अनुमति देता है क्योंकि उन पंक्तियों को डुप्लिकेट चेकिंग से पूरी तरह से छोड़ दिया जाता है। एक अतिरिक्त बोनस के रूप में, यह एक छोटी अनुक्रमणिका के रूप में होता है, जिसमें एक से अधिक तालिकाएँ होती हैं यदि एकाधिक NULLs की अनुमति होती है (विशेषकर जब यह सूचकांक में एकमात्र स्तंभ नहीं होता है, तो इसमें INCLUDEकॉलम आदि होते हैं)। हालाँकि, आप फ़िल्टर्ड अनुक्रमित की कुछ अन्य सीमाओं से अवगत होना चाहते हैं:


8

सही बात। Sql सर्वर में एक अद्वितीय बाधा या सूचकांक के कार्यान्वयन से एक और केवल एक NULL की अनुमति मिलती है। यह भी सही है कि यह तकनीकी रूप से NULL की परिभाषा के साथ फिट नहीं है, लेकिन यह उन चीजों में से एक है, जिन्होंने इसे "तकनीकी रूप से" सही नहीं होने के बावजूद इसे और अधिक उपयोगी बनाने के लिए किया। ध्यान दें एक प्राथमिक कुंजी (एक अद्वितीय सूचकांक भी) NULLs (बेशक) की अनुमति नहीं देता है।


1
यह (SQL-Server) तकनीकी भी SQL मानक के साथ फिट नहीं है। इस मुद्दे के बारे में 7 साल पुराना कनेक्ट आइटम है
ypercube y

@ypercube ट्रू। इसलिए मैंने कहा कि यह सिर्फ कार्यान्वयन था और वास्तव में NULL की परिभाषा में फिट नहीं होता है। मैंने फ़िल्टर्ड यूनिक इंडेक्स के बारे में नहीं सोचा था (हालाँकि मैंने इसका इस्तेमाल दूसरी चीज़ों के लिए किया है।)
केनेथ फिशर

3

पहला - "अशक्त मूल्य" वाक्यांश का उपयोग करना बंद करें, यह आपको भटका देगा। इसके बजाय, वाक्यांश "अशक्त मार्कर" का उपयोग करें - एक स्तंभ में एक मार्कर जो यह दर्शाता है कि इस स्तंभ में वास्तविक मूल्य या तो गायब है या अनुपयुक्त है (लेकिन ध्यान दें कि मार्कर यह नहीं कहता है कि वास्तव में उन विकल्पों में से कौन सा मामला है)।

अब, निम्नलिखित की कल्पना करें (जहां डेटाबेस को मॉडलिंग की स्थिति का पूरा ज्ञान नहीं है)।

Situation          Database

ID   Code          ID   Code
--   -----         --   -----
1    A             1    A
2    B             2    (null)
3    C             3    C
4    B             4    (null)

अखंडता नियम जो हम मॉडलिंग कर रहे हैं वह है "कोड अद्वितीय होना चाहिए"। वास्तविक दुनिया की स्थिति इसका उल्लंघन करती है, इसलिए डेटाबेस को आइटम 2 और 4 दोनों को एक ही समय में तालिका में नहीं रखने देना चाहिए।

सबसे सुरक्षित और कम से कम लचीला, दृष्टिकोण कोड क्षेत्र में अशक्त मार्करों को अस्वीकार करना होगा, इसलिए असंगत डेटा की कोई संभावना नहीं है। सबसे लचीला दृष्टिकोण कई शून्य मार्करों की अनुमति देना और मूल्यों में प्रवेश करने पर विशिष्टता के बारे में चिंता करना होगा।

सिबेस के प्रोग्रामर टेबल में केवल एक अशक्त मार्कर की अनुमति देने के लिए कुछ हद तक सुरक्षित, नहीं-बहुत-लचीले दृष्टिकोण के साथ गए - कुछ टिप्पणीकारों ने तब से शिकायत की है। Microsoft ने इस व्यवहार को जारी रखा है, मुझे लगता है कि पश्चगामी संगतता है।


Two मुझे यकीन है कि मैंने कहीं पढ़ा है कि कॉड ने दो अशक्त मार्करों को लागू करने पर विचार किया - एक अज्ञात के लिए, एक अनुपयुक्त के लिए - लेकिन इसे अस्वीकार कर दिया, लेकिन मुझे संदर्भ नहीं मिल रहा है। क्या मुझे सही याद है?

PS मेरा पसंदीदा उद्धरण अशक्त के बारे में: लुई डेविडसन, "प्रोफेशनल SQL सर्वर 2000 डेटाबेस डिज़ाइन", Wrox प्रेस, 2001, पृष्ठ 52. "एक वाक्य के लिए उबला हुआ: NULL बुराई है।"


1
एकल की अनुमति देने से nullयह लक्ष्य प्राप्त नहीं होता है। क्योंकि अनुपलब्ध मान अन्य पंक्तियों में से एक मान के समान हो सकता है।
मार्टिन स्मिथ

1
@MartinSmith ने क्या कहा। यदि आपके पास एक चेक बाधा है तो क्या होगा CHECK (Value IN ('A','B','C','D'))? फिर SQL- सर्वर के कार्यान्वयन और SQL मानक दोनों तालिका को 5 पंक्तियों (NULL के साथ प्रत्येक मान 1 के लिए एक पंक्ति) की अनुमति देते हैं। फिर, यकीनन, जबकि डेटाबेस अपने अवरोधों के अनुरूप है, यह डिज़ाइनर के इरादे के अनुरूप नहीं है। तालिका में अधिकतम 4 पंक्तियाँ हैं। इसका कोई मूल्य नहीं है कि NULL को उस में बदला जा सकता है, जब तक कि एक या अधिक पंक्तियों को हटा नहीं दिया जाता, एक बाधा का उल्लंघन नहीं करेगा।
ypercube y

1
तथ्य यह है कि मानक 5 के बजाय 6 की 106 पंक्तियों को भी बदलने की अनुमति नहीं देता है कि वे दोनों इस परिदृश्य में किसी तरह से विफल हो जाते हैं।
ypercube y

@ मर्टिन स्मिथ, यह हो सकता है, लेकिन फिर, यह नहीं हो सकता है - डेटाबेस सर्वर नहीं बता सकता है इसलिए यह इसे जोखिम नहीं देता है और सुरक्षित मार्ग लेता है। यही कारण है कि Sybase (मुझे लगता है) प्रोग्रामर ने फैसला किया, जिससे कभी नाराजगी पैदा हुई (कम से कम जहाँ तक एसक्यूएल सर्वर 6.5 के रूप में, मेरे बुकशेल्फ़ पर सबसे पुरानी किताब, जहाँ रॉन सूकूप वही टिप्पणी करते हैं जो हारून बर्टेंड ने अपने जवाब में की है) । मुझे लगता है कि यह बदतर हो सकता है - वे कोई शून्य मार्करों को अनिवार्य कर सकते थे। :-)
ग्रीनस्टोन वाकर

2
@GreenstoneWalker - यह "सुरक्षित" मार्ग नहीं लेता है। यह मानता है कि लापता मूल्य संघर्ष नहीं करेगा। CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;कोई त्रुटि उठाएगा। आपके द्वारा डिजाइन किए गए प्रेरणा के सिद्धांत के अनुसार NULLपहले मामले में सम्मिलन को रोकना चाहिए - क्योंकि अपूर्ण ज्ञान का अर्थ है कि कोई गारंटी नहीं है कि मूल्य अलग है।
मार्टिन स्मिथ

2

यह तकनीकी रूप से सटीक नहीं हो सकता है, लेकिन दार्शनिक रूप से यह मुझे रात में सोने में मदद करता है ...

जैसे कई अन्य ने कहा है या के लिए कहा गया है, यदि आप NULL को अज्ञात मानते हैं, तो आप यह निर्धारित नहीं कर सकते कि एक NULL मान वास्तव में दूसरे NULL मान के बराबर है या नहीं। इसे इस तरह से सोचकर, NULL == NULL को NULL का मूल्यांकन करना चाहिए, जिसका अर्थ अज्ञात है।

स्तंभ मानों की तुलना के लिए एक अद्वितीय बाधा को एक निश्चित मान की आवश्यकता होगी। दूसरे शब्दों में, समानता ऑपरेटर का उपयोग करके किसी भी अन्य स्तंभ मान के खिलाफ एकल स्तंभ मान की तुलना करते समय, इसे मान्य होने के लिए गलत का मूल्यांकन करना होगा। अज्ञात वास्तव में गलत नहीं है भले ही इसे अक्सर झूठा माना जाता है। दो पूर्ण मान समान हो सकते हैं, या नहीं ... यह केवल निश्चित रूप से निर्धारित नहीं किया जा सकता है।

यह एक अद्वितीय बाधा के रूप में उन मूल्यों को प्रतिबंधित करने में मदद करता है जिन्हें एक दूसरे से अलग होने के लिए निर्धारित किया जा सकता है। इसका मतलब क्या है अगर आप एक SELECT चलाते हैं जो कुछ इस तरह दिखता है:

SELECT * from dbo.table1 WHERE ColumnWithUniqueContraint="some value"

अधिकांश लोग एक परिणाम की उम्मीद करेंगे, यह देखते हुए कि एक अद्वितीय बाधा है। यदि आपने ColumnWithUniqueConstraint में एकाधिक NULL मानों को अनुमति दी है, तो NULL का उपयोग किए गए मान के रूप में तालिका से एक अलग पंक्ति का चयन करना असंभव होगा।

यह देखते हुए, मेरा मानना ​​है कि NULL की परिभाषा के सम्मान के साथ इसे सही ढंग से लागू किया गया है या नहीं, इसकी परवाह किए बिना, यह निश्चित रूप से कई स्थितियों में कई अधिक व्यावहारिक मूल्यों की अनुमति देने की तुलना में अधिक व्यावहारिक है।


आपका चयन 1 परिणाम देगा, जब कोई विशिष्ट बाधा हो (किसी भी कार्यान्वयन में, न केवल SQL- सर्वर)। तुम्हारा मतलब क्या है?
ypercube y

-3

एक UNIQUEबाधा के प्रमुख उद्देश्यों में से एक डुप्लिकेट रिकॉर्ड को रोकने के लिए है। यदि किसी को एक तालिका रखने की आवश्यकता होती है जिसमें कई रिकॉर्ड हो सकते हैं जहां एक मान "अज्ञात" है, लेकिन किसी भी दो रिकॉर्ड को समान "ज्ञात" मान रखने की अनुमति नहीं है, तो अज्ञात मानों को कृत्रिम अद्वितीय पहचानकर्ता को सौंपा जाना चाहिए। तालिका में जोड़ा गया।

कुछ दुर्लभ मामले हैं जिनमें एक स्तंभ जिसमें एक UNIQUEबाधा होती है और एक एकल अशक्त मान होता है; उदाहरण के लिए, यदि किसी तालिका में स्तंभ मानों और स्थानीय पाठ विवरणों के बीच मानचित्रण होता है, तो उस पंक्ति NULLको उस विवरण को परिभाषित करना संभव होगा जो किसी अन्य तालिका में उस स्तंभ के दिखाई देने पर होना चाहिए NULLNULLउस उपयोग के मामले के लिए अनुमति देता है का व्यवहार ।

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


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

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

@AaronBertrand: कुछ मामले ऐसे होते हैं, जहाँ संभवतः एक अशक्त अद्वितीय-अगर-नहीं-शून्य क्षेत्र को सरोगेट कुंजी बनाने की आवश्यकता होगी, जो क्षेत्र को आबाद करने से पहले स्थापित नहीं की जा सकती है (उदाहरण के लिए "पति-पत्नी आईडी"), लेकिन जैसी स्थितियों में एक "अद्वितीय" बाधा अपर्याप्त होगी; यह आवश्यक होगा कि यदि X.Spouse गैर-शून्य है, X.Spouse.Spouse = X। संयोग से, "पति / पत्नी" जैसी कोई चीज यह कहकर भी संभाला जा सकता है कि अविवाहित व्यक्ति के लिए रिकॉर्ड पति / पत्नी के रूप में "NULL" नहीं होना चाहिए, बल्कि उसकी अपनी आईडी, जिसमें X.spouse.spouse = X नियम हो। सभी पर लागू होता है।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.