PostgreSQL बहु-स्तंभ अद्वितीय बाधा और पूर्ण मान


93

मेरे पास निम्नलिखित की तरह एक तालिका है:

create table my_table (
    id   int8 not null,
    id_A int8 not null,
    id_B int8 not null,
    id_C int8 null,
    constraint pk_my_table primary key (id),
    constraint u_constrainte unique (id_A, id_B, id_C)
);

और मैं (id_A, id_B, id_C)किसी भी स्थिति में अलग होना चाहता हूं । तो निम्नलिखित दो आवेषण में त्रुटि हो सकती है:

INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);

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

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


तो, आप मान का कहना है कि (1,2,1)और (1,2,2)में (A,B,C)कॉलम। (1,2,NULL)जोड़ने की अनुमति दी जानी चाहिए या नहीं?
ypercube y

A और B शून्य नहीं हो सकते लेकिन C शून्य या कोई धनात्मक पूर्णांक मान हो सकता है। तो (1,2,3) और (2,4, अशक्त) मान्य हैं लेकिन (अशक्त, 2,3) या (1, अशक्त, 4) अमान्य हैं। और [(1,2, null), (1,2,3)] अद्वितीय बाधा को नहीं तोड़ता है लेकिन [(1,2, null), (1,2, null)] को इसे तोड़ना चाहिए।
मैनुअल लेडुक

2
क्या कोई ऐसा मान है जो उन कॉलमों में कभी नहीं दिखाई देगा (जैसे नकारात्मक मान?)
a_horse_with_no_name

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

जवाबों:


93

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

CREATE UNIQUE INDEX ab_c_null_idx ON my_table (id_A, id_B) WHERE id_C IS NULL;

इस तरह से आप (a, b, c)अपनी तालिका में प्रवेश कर सकते हैं :

(1, 2, 1)
(1, 2, 2)
(1, 2, NULL)

लेकिन इनमें से कोई भी दूसरी बार नहीं।

या दो आंशिक UNIQUEसूचकांक और पूर्ण सूचकांक (या बाधा) का उपयोग करें। सबसे अच्छा समाधान आपकी आवश्यकताओं के विवरण पर निर्भर करता है। की तुलना करें:

हालांकि यह UNIQUEसूचकांक में एक एकल अशक्त स्तंभ के लिए एक कुशल है , यह अधिक के लिए जल्दी से हाथ से निकल जाता है। इस पर चर्चा - और आंशिक अनुक्रमित के साथ यूपीएसईआरटी का उपयोग कैसे करें:

Asides

PostgreSQL में दोहरे उद्धरण चिह्नों के बिना मिश्रित मामले के पहचानकर्ताओं के लिए कोई उपयोग नहीं ।

आप स्तंभ को प्राथमिक कुंजी या स्तंभ को 10 या बाद के संस्करण के रूप में मान सकते हैं । सम्बंधित:serialIDENTITY

इसलिए:

CREATE TABLE my_table (
   my_table_id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY  -- for pg 10+
-- my_table_id bigserial PRIMARY KEY  -- for pg 9.6 or older
 , id_a int8 NOT NULL
 , id_b int8 NOT NULL
 , id_c int8
 , CONSTRAINT u_constraint UNIQUE (id_a, id_b, id_c)
);

यदि आप अपनी तालिका के जीवनकाल में 2 बिलियन से अधिक पंक्तियों (> 2147483647) (बेकार और हटाई गई पंक्तियों सहित) की अपेक्षा नहीं करते हैं, तो integer(8 बाइट्स) के बजाय 4 बाइट्स पर विचार करें bigint


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

12

मेरे पास एक ही समस्या थी और मुझे तालिका में अद्वितीय NULL होने का एक और तरीका मिला।

CREATE UNIQUE INDEX index_name ON table_name( COALESCE( foreign_key_field, -1) )

मेरे मामले में, क्षेत्र foreign_key_fieldएक सकारात्मक पूर्णांक है और कभी भी -1 नहीं होगा।

इसलिए, मैनुअल लेडुक का उत्तर देने के लिए, एक और समाधान हो सकता है

CREATE UNIQUE INDEX  u_constrainte (COALESCE(id_a, -1), COALESCE(id_b,-1),COALESCE(id_c, -1) )

मुझे लगता है कि आईडी -1 नहीं होगा।

आंशिक सूचकांक बनाने पर क्या फायदा है?
ऐसे मामले में जहां आपके पास नॉट NULL क्लॉज नहीं है id_a, id_bऔर id_cकेवल एक बार NULL हो सकता है।
आंशिक सूचकांक के साथ, 3 फ़ील्ड एक से अधिक बार NULL हो सकते हैं।


3
> आंशिक सूचकांक बनाने पर क्या फायदा है? जिस तरह से आपने इसे किया है वह COALESCEडुप्लिकेट को प्रतिबंधित करने में प्रभावी हो सकता है, लेकिन इंडेक्स क्वेरी में बहुत उपयोगी नहीं होगा क्योंकि यह एक अभिव्यक्ति इंडेक्स है जो शायद क्वेरी के भावों से मेल नहीं खाएगा। यह है, जब तक कि आप SELECT COALESCE(col, -1) ...इंडेक्स को नहीं मारेंगे।
बो जीनस

@BoJeanes प्रदर्शन समस्या के लिए अनुक्रमणिका नहीं बनाई गई है। यह व्यवसाय की आवश्यकता को पूरा करने के लिए बनाया गया है।
ल्यूक एम

8

अशक्त का अर्थ यह हो सकता है कि उस समय उस पंक्ति के लिए मान ज्ञात नहीं है, लेकिन भविष्य में ( FinishDateकिसी रनिंग के लिए उदाहरण Project) ज्ञात होने पर या उस पंक्ति के लिए कोई मूल्य लागू नहीं किया जा सकता (उदाहरण के EscapeVelocityलिए, ब्लैक होल के लिए Star) जोड़ा जाएगा ।

मेरी राय में, आमतौर पर सभी नल को समाप्त करके तालिकाओं को सामान्य करना बेहतर होता है।

आपके मामले में, आप NULLsअपने कॉलम में अनुमति देना चाहते हैं , फिर भी आप केवल एक NULLको अनुमति देना चाहते हैं । क्यों? यह दो तालिकाओं के बीच किस तरह का संबंध है?

शायद आप केवल एक विशेष मान (जैसे ) के NOT NULLबजाय कॉलम को स्टोर और स्टोर में बदल सकते हैं, जो कभी भी प्रकट नहीं होता है। यह विशिष्टता की बाधा समस्या को हल करेगा (लेकिन इसके अन्य संभावित अवांछित दुष्प्रभाव हो सकते हैं। उदाहरण के लिए, "ज्ञात नहीं है / लागू नहीं होता है" का उपयोग करने से स्तंभ पर कोई योग या औसत गणना तिरछी हो जाएगी। या ऐसी सभी गणनाओं को लेना होगा। विशेष मूल्य को ध्यान में रखें और इसे अनदेखा करें।)NULL-1-1


2
मेरे मामले में NULL वास्तव में NULL है (id_C एक विदेशी कुंजी है टेबल के लिए (इसलिए यह -1 मान नहीं हो सकता है), इसका मतलब है कि उनका "my_table" और "table_c" के बीच कोई संबंध नहीं है। तो यह एक कार्यात्मक संकेत है। वैसे [(1, 1,1, नल), (2, 1,2, नल), (3,2,4, नल)] सम्मिलित डेटा की एक वैध सूची है।
मैनुअल लेडुक

1
यह वास्तव में Null नहीं है जैसा कि SQL में उपयोग किया जाता है क्योंकि आप सभी पंक्तियों में केवल एक चाहते हैं। आप अपने डेटाबेस स्कीमा को -1 में जोड़कर table_c जोड़ सकते हैं या किसी अन्य तालिका को जोड़ सकते हैं (जो table_c को उपप्रकार करने के लिए सुपरपेप्ट होगा)।
ypercube y

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

1
जब आपका कॉलम FOREIGN KEY हो तो आप डमी वैल्यू का उपयोग नहीं कर सकते।
ल्यूक एम

1
+1 मैं आपके साथ हूं: यदि हम स्तंभों के कुछ संयोजन को अद्वितीय बनाना चाहते हैं, तो आपको एक इकाई पर विचार करने की आवश्यकता है जिसमें स्तंभों का यह संयोजन एक पीके है। ओप्स के डेटाबेस स्कीमा को संभवतः मूल तालिका और बच्चे के लिए बदलना चाहिए।
AK
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.