समग्र प्राथमिक कुंजियों में अशक्त स्तंभों के साथ क्या गलत है?


149

ORACLE प्राथमिक कुंजी वाले किसी भी स्तंभ में पूर्ण मानों की अनुमति नहीं देता है। ऐसा प्रतीत होता है कि अधिकांश अन्य "एंटरप्राइज-लेवल" सिस्टम के बारे में भी यही सच है।

इसी समय, अधिकांश प्रणालियां अशक्त स्तंभों पर अद्वितीय विरोधाभासों की भी अनुमति देती हैं।

ऐसा क्यों है कि अद्वितीय बाधाओं में NULLs हो सकते हैं लेकिन प्राथमिक कुंजी नहीं हो सकती? क्या इसका कोई मूलभूत तार्किक कारण है, या यह एक तकनीकी सीमा है?


जवाबों:


216

प्राथमिक कुंजियाँ विशिष्ट पहचान वाली पंक्तियों के लिए हैं। यह कुंजी के सभी भागों की इनपुट से तुलना करके किया जाता है।

परिभाषा के अनुसार, NULL एक सफल तुलना का हिस्सा नहीं हो सकता। यहां तक ​​कि खुद की तुलना ( NULL = NULL) विफल हो जाएगी। इसका मतलब है कि NULL युक्त कुंजी काम नहीं करेगी।

वैकल्पिक रूप से, वैकल्पिक संबंध को चिह्नित करने के लिए, NULL को एक विदेशी कुंजी में अनुमति दी जाती है। (*) इसे पीके में देने से यह टूट जाएगा।


(*) सावधानी का एक शब्द: अशक्त विदेशी कुंजी होने से स्वच्छ संबंधपरक डेटाबेस डिज़ाइन नहीं है।

यदि दो संस्थाएँ हैं Aऔर Bजहाँ Aवैकल्पिक रूप से संबंधित किया जा सकता है B, तो स्वच्छ समाधान एक रिज़ॉल्यूशन टेबल बनाना है (मान लीजिए AB)। यही कारण है कि तालिका लिंक होगा Aसाथ B: अगर है एक रिश्ता तो यह एक रिकॉर्ड होते हैं, अगर वहाँ नहीं है तो ऐसा नहीं है।


5
मैंने इसका उत्तर स्वीकार कर लिया है। वोटों को देखते हुए, यह जवाब अधिक लोगों को स्पष्ट है। मुझे अभी भी लगता है कि टोनी एंड्रयूज का जवाब इस डिजाइन के पीछे के इरादे को बेहतर बताता है; इसे भी देखें!
रोमन स्टार्कोव

2
प्रश्न: आप पंक्ति की कमी के बजाय NULL FK कब चाहते हैं? A: अनुकूलन के लिए केवल स्कीमा के एक संस्करण में, जिसे असामान्य रूप से विभाजित किया गया है। गैर-तुच्छ स्कीमाओं में इस तरह के अप्राकृतिक मुद्दे जब भी नई सुविधाओं की आवश्यकता होती है, तो समस्याएं हो सकती हैं। ओट, वेब डिज़ाइन की भीड़ परवाह नहीं करती है। मैं कम से कम इसे एक अच्छे डिजाइन विचार की तरह ध्वनि बनाने के बजाय इसके बारे में सावधानी से जोड़ूंगा।
zxq9

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

1
क्या होगा अगर यह एबीसी रिज़ॉल्यूशन टेबल है? वैकल्पिक सी के साथ
बार्ट कैलिक्सो

1
मैंने लिखने से बचने की कोशिश की "क्योंकि मानक इसे मना करता है", क्योंकि यह वास्तव में कुछ भी नहीं समझाता है।
तोमलक

62

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

एक अद्वितीय बाधा जरूरी नहीं कि हर पंक्ति की पहचान करे; यह केवल यह निर्दिष्ट करता है कि यदि किसी पंक्ति के स्तंभों में मान हैं, तो वे अद्वितीय होने चाहिए। यह हर पंक्ति को विशिष्ट रूप से पहचानने के लिए पर्याप्त नहीं है , जो कि एक प्राथमिक कुंजी को करना चाहिए।


10
Sql सर्वर में एक अद्वितीय बाधा है जिसमें एक अशक्त स्तंभ है, केवल उस स्तंभ में 'null' मान की अनुमति देता है (बाधा के अन्य स्तंभों के लिए समान मान दिए गए)। तो इस तरह के एक अद्वितीय बाधा अनिवार्य रूप से एक अशक्त स्तंभ के साथ एक पीके की तरह व्यवहार करता है।
जेरार्ड


2
Oracle में (मैं SQL सर्वर के बारे में नहीं जानता), तालिका में कई पंक्तियाँ हो सकती हैं जहाँ एक अद्वितीय बाधा में सभी कॉलम अशक्त हैं। हालांकि, यदि अद्वितीय अवरोध में कुछ स्तंभों को शून्य नहीं किया गया है और कुछ अशक्त हैं तो विशिष्टता को लागू किया गया है।
टोनी एंड्रयूज

यह समग्र UNIQUE पर कैसे लागू होता है?
डेम्स

1
@Dims SQL डेटाबेस में लगभग कुछ और के साथ "यह कार्यान्वयन पर निर्भर करता है"। अधिकांश dbs में एक "प्राथमिक कुंजी" वास्तव में एक अड़चन है। "प्राथमिक कुंजी" का विचार वास्तव में UNIQUE की अवधारणा से अधिक विशेष या शक्तिशाली नहीं है। वास्तविक अंतर यह है कि यदि आपके पास एक तालिका के दो स्वतंत्र पहलू हैं जो कि UNIQUE की गारंटी दे सकते हैं तो आपके पास परिभाषा द्वारा एक सामान्यीकृत डेटाबेस नहीं है (आप एक ही तालिका में दो प्रकार के डेटा संग्रहीत कर रहे हैं)।
zxq9

46

बहु-स्तंभ प्राथमिक कुंजी में NULL के साथ मौलिक रूप से कुछ भी गलत नहीं है। लेकिन एक होने का मतलब है कि डिजाइनर की यह मंशा नहीं थी, यही वजह है कि जब आप यह कोशिश करते हैं तो कई सिस्टम एक त्रुटि फेंक देते हैं।

खेतों की एक श्रृंखला के रूप में संग्रहीत मॉड्यूल / पैकेज संस्करणों के मामले पर विचार करें:

CREATE TABLE module
  (name        varchar(20) PRIMARY KEY,
   description text DEFAULT '' NOT NULL);

CREATE TABLE version
  (module      varchar(20) REFERENCES module,
   major       integer NOT NULL,
   minor       integer DEFAULT 0 NOT NULL,
   patch       integer DEFAULT 0 NOT NULL,
   release     integer DEFAULT 1 NOT NULL,
   ext         varchar(20),
   notes       text DEFAULT '' NOT NULL,
   PRIMARY KEY (module, major, minor, patch, release, ext));

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

लेकिन NULL क्या है ? यह जानकारी की कमी का प्रतिनिधित्व करने वाला है , एक अज्ञात। उस ने कहा, शायद यह अधिक समझ में आता है:

CREATE TABLE version
  (module      varchar(20) REFERENCES module,
   major       integer NOT NULL,
   minor       integer DEFAULT 0 NOT NULL,
   patch       integer DEFAULT 0 NOT NULL,
   release     integer DEFAULT 1 NOT NULL,
   ext         varchar(20) DEFAULT '' NOT NULL,
   notes       text DEFAULT '' NOT NULL,
   PRIMARY KEY (module, major, minor, patch, release, ext));

इस संस्करण में टपल का "एक्सट" हिस्सा NULL नहीं है, लेकिन खाली स्ट्रिंग में चूक है - जो शब्दार्थ (और व्यावहारिक रूप से) NULL से अलग है। NULL एक अज्ञात है, जबकि एक खाली स्ट्रिंग "कुछ मौजूद नहीं है" का एक जानबूझकर रिकॉर्ड है। दूसरे शब्दों में, "खाली" और "अशक्त" अलग-अलग चीजें हैं। इसका अंतर "मुझे यहाँ कोई मूल्य नहीं है" और "मुझे नहीं पता कि यहाँ क्या मूल्य है।"

जब आप एक पैकेज को पंजीकृत करते हैं जिसमें एक संस्करण एक्सटेंशन का अभाव होता है तो आपको पता है कि इसमें एक एक्सटेंशन का अभाव है, इसलिए एक खाली स्ट्रिंग वास्तव में सही मूल्य है। एक NULL केवल तभी सही होगा जब आपको पता नहीं था कि इसमें कोई एक्सटेंशन है या नहीं, या आप जानते हैं कि यह किया था लेकिन यह नहीं जानता था कि यह क्या था। यह स्थिति उन प्रणालियों से निपटने में आसान है जहां स्ट्रिंग मान आदर्श हैं, क्योंकि 0 या 1 डालने के अलावा "खाली पूर्णांक" का प्रतिनिधित्व करने का कोई तरीका नहीं है, जो बाद में किए गए किसी भी तुलना में लुढ़का होगा (जो है) अपने स्वयं के निहितार्थ) *।

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

पोस्टग्रेज मानते हैं कि आप एक वयस्क हैं और अपने लिए यह निर्णय ले सकते हैं। ओरेकल और डीबी 2 मान लेते हैं कि आपको एहसास नहीं हुआ कि आप कुछ मूर्खतापूर्ण कर रहे हैं और एक त्रुटि है। ये है आमतौर पर सही बात है, लेकिन हमेशा नहीं - आप वास्तव में नहीं जानते हैं और कुछ मामलों में NULL हो सकते हैं और इसलिए एक अज्ञात तत्व के साथ एक पंक्ति छोड़ना जिसके खिलाफ सार्थक तुलना असंभव है सही व्यवहार है।

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

[* नोट: एक कस्टम प्रकार बनाना संभव है जो पूर्णांकों का संघ है और एक "निचला" प्रकार है जो "अज्ञात" के विपरीत "खाली" शब्द का अर्थ होगा। दुर्भाग्य से यह तुलनात्मक संचालन में थोड़ी जटिलता का परिचय देता है और आमतौर पर सही प्रकार से सही होना व्यवहार में प्रयास के लायक नहीं है क्योंकि आपको NULLपहली बार में कई मूल्यों की अनुमति नहीं दी जानी चाहिए । उस ने कहा, यह बहुत अच्छा होगा यदि RDBMS में "अज्ञात मान" के साथ "नो वैल्यू" के शब्दार्थ को अनौपचारिक रूप से भ्रमित करने की आदत को रोकने के BOTTOMअलावा एक डिफ़ॉल्ट प्रकार शामिल होगा NULL]


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

मैं इस उत्तर के मुख्य विचार का समर्थन करता हूं। लेकिन 'एक जानकारी की कमी का प्रतिनिधित्व करने वाला, एक अज्ञात', 'शब्दार्थ (और व्यावहारिक रूप से) एक NULL से अलग', 'A NULL एक अज्ञात है', जैसे लेखन एक खाली स्ट्रिंग "कुछ मौजूद नहीं है" का एक जानबूझकर रिकॉर्ड है ", '' NULL ==" पता नहीं ", आदि अस्पष्ट और भ्रामक हैं और वास्तव में अनुपस्थित कथनों के लिए केवल mnemonics फिर से कैसे NULL या कोई मूल्य है या उपयोग करने का इरादा था - बाकी पोस्ट के अनुसार । (एसक्यूएल NULL सुविधाओं की (खराब) डिजाइन को प्रेरित करने में शामिल हैं।) वे किसी भी चीज़ को सही या स्पष्ट नहीं करते हैं; उन्हें समझाया जाना चाहिए और डिबंक किया जाना चाहिए।
दीक्षा

21

NULL == NULL -> गलत (कम से कम DBMS में)

इसलिए आप वास्तविक मूल्यों के साथ अतिरिक्त कॉलम के साथ भी NULL मान का उपयोग करके किसी भी रिश्ते को पुनः प्राप्त नहीं कर पाएंगे।


1
यह सबसे अच्छा उत्तर लगता है, लेकिन मुझे अभी भी समझ में नहीं आया कि प्राथमिक कुंजी निर्माण पर यह क्यों निषिद्ध है। यदि यह सिर्फ एक पुनर्प्राप्ति समस्या थी, तो आप where pk_1 = 'a' and pk_2 = 'b'सामान्य मानों के साथ उपयोग कर सकते हैं , और where pk_1 is null and pk_2 = 'b'जब नल हो तो स्विच कर सकते हैं।
EoghanM

या इससे भी अधिक मज़बूती से, where (a.pk1 = b.pk1 or (a.pk1 is null and b.pk1 is null)) and (a.pk2 = b.pk2 or (a.pk2 is null and b.pk2 is null))/
जॉर्डन रीगर

8
गलत जवाब। NULL == NULL -> UNKNOWN। असत्य नहीं। पकड़ यह है कि यदि परीक्षा का परिणाम UNKNOWN है तो एक बाधा का उल्लंघन नहीं माना जाता है। यह अक्सर इसे SEEM बनाता है जैसे कि तुलना गलत देती है, लेकिन यह वास्तव में नहीं करता है।
इरविन स्मौट

4

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

UNKNOWN (3rd सत्य मूल्य) में NULL परिणामों के लिए कुछ भी तुलना करना। तो जैसा कि nulls के साथ सुझाव दिया गया है कि समानता के संबंध में सभी पारंपरिक ज्ञान खिड़की से बाहर चले जाते हैं। वैसे यह पहली नज़र में कैसा लगता है।

लेकिन मुझे नहीं लगता कि ऐसा जरूरी है और यहां तक ​​कि SQL डेटाबेस भी नहीं सोचते कि NULL तुलना के लिए सभी संभावना को नष्ट कर देता है।

अपने डेटाबेस में क्वेरी का चयन करें * वाल्व से (NULL) यूनिअन का चयन करें * वाल्व से (NULL)

आप जो देख रहे हैं, वह केवल एक विशेषता है, जिसकी एक विशेषता है जिसका मान NULL है। इसलिए संघ ने यहां दो NULL मूल्यों को समान माना।

जब एक कंपोज़िट कुंजी की तुलना की जाती है जिसमें 3 गुणनखंड (1, 3, NULL) = (1, 3, NULL) के साथ 3 घटक होते हैं, तो <=> 1 = 1 और 3 = 3 और NULL = NULL इस का परिणाम UNKNOWN है ।

लेकिन हम एक नए तरह के तुलना ऑपरेटर को परिभाषित कर सकते हैं। ==। X == Y <=> X = Y OR (X IS NULL AND Y IS NULL)

इस तरह की समानता ऑपरेटर होने से अशक्त घटकों के साथ संयुक्त कुंजी या अशक्त मूल्य के साथ गैर-संयुक्त कुंजी अप्रमाणिक बन जाएगी।


1
नहीं, UNION ने दोनों NULL को गैर-विशिष्ट के रूप में मान्यता दी है। जो "समान" के समान नहीं है। इसके बजाय UNION ALL आज़माएँ और आपको दो पंक्तियाँ मिलेंगी। और "नए प्रकार के तुलना ऑपरेटर" के लिए, SQL में पहले से ही है। DISTINCT FROM नहीं है। लेकिन वह अपने आप में पर्याप्त नहीं है। SQL कंस्ट्रक्शन जैसे कि NATURAL JOIN, या किसी विदेशी कुंजी के REFERENCES क्लॉज में इसका उपयोग करने पर उन कंस्ट्रक्शन पर अतिरिक्त विकल्पों की आवश्यकता होगी।
इरविन स्मौट

अहा, इरविन स्माउट। सचमुच इस मंच पर आपसे मिलकर खुशी हुई! मुझे SQL के "IS NOT DISTINCT FROM" के बारे में पता नहीं था। बहुत ही रोचक! लेकिन ऐसा लगता है कि यह वही है जो मैं अपने बनाये हुए == ऑपरेटर के साथ था। क्या आप मुझे समझा सकते हैं कि आप ऐसा क्यों कहते हैं: "जो अपने आप में पर्याप्त नहीं है"?
रामी ओजरेस

परिभाषा के अनुसार, खंड समानता पर बनाता है। इस तरह के संदर्भ जो एक माता-पिता / पंक्ति के साथ एक बच्चे के ट्यूपल / पंक्ति से मेल खाते हैं, इसी विशेषता मूल्यों के आधार पर DISTINCT नहीं है (सख्त) EQUAL के बजाय, इस विकल्प को निर्दिष्ट करने की क्षमता की आवश्यकता होगी, लेकिन वाक्यविन्यास नहीं करता है इसे अनुमति दें। प्राकृतिक जॉय के लिए डिट्टो।
इरविन स्मॉर्ट

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

1

मैं अभी भी मानता हूं कि यह एक तकनीकी द्वारा लाया गया एक मौलिक / कार्यात्मक दोष है। यदि आपके पास एक वैकल्पिक क्षेत्र है जिसके द्वारा आप एक ग्राहक की पहचान कर सकते हैं जिसे आपको अब इसमें एक डमी मूल्य को हैक करना है, सिर्फ इसलिए कि NULL! = NULL, विशेष रूप से सुरुचिपूर्ण नहीं है फिर भी यह एक "उद्योग मानक" है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.