PostgreSQL में कई-से-कई संबंध कैसे लागू करें?


94

मेरा मानना ​​है कि शीर्षक स्व-व्याख्यात्मक है। आप कई-से-कई संबंध बनाने के लिए PostgreSQL में तालिका संरचना कैसे बनाते हैं।

मेरा उदाहरण:

Product(name, price);
Bill(name, date, Products);

2
बिल तालिका से उत्पादों को हटा दें, दो क्षेत्रों के साथ "बिल_प्रोडक्ट्स" नामक एक नई तालिका बनाएं: एक उत्पाद की ओर इशारा करते हुए, एक बिल की ओर इशारा करते हुए। उन दो क्षेत्रों को इस नई तालिका की प्राथमिक कुंजी बनाएं।
मार्क बी

तो बिल_प्रोडक्ट (बिल, उत्पाद); ? और दोनों पीके?
रादु घोरघिउ

1
हाँ। वे व्यक्तिगत रूप से अपने संबंधित तालिकाओं पर इशारा करते हुए एक एफके होंगे, और साथ में वे नई तालिका के लिए पीके होंगे।
मार्क बी

तो, बिल_प्रोडक्ट (उत्पाद संदर्भ product.name, बिल संदर्भ बिल ।name, (उत्पाद, बिल) प्राथमिक कुंजी)?
रादु घोरघिउ

वे उत्पाद और बिल तालिकाओं के पीके खेतों को इंगित करेंगे।
मार्क बी

जवाबों:


297

SQL DDL (डेटा परिभाषा भाषा) कथन इस तरह दिख सकते हैं:

CREATE TABLE product (
  product_id serial PRIMARY KEY  -- implicit primary key constraint
, product    text NOT NULL
, price      numeric NOT NULL DEFAULT 0
);

CREATE TABLE bill (
  bill_id  serial PRIMARY KEY
, bill     text NOT NULL
, billdate date NOT NULL DEFAULT CURRENT_DATE
);

CREATE TABLE bill_product (
  bill_id    int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE
, product_id int REFERENCES product (product_id) ON UPDATE CASCADE
, amount     numeric NOT NULL DEFAULT 1
, CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id)  -- explicit pk
);

मैंने कुछ समायोजन किए:

  • N: मीटर संबंध सामान्य रूप से एक अलग तालिका द्वारा कार्यान्वित किया जाता - bill_productइस मामले में।

  • मैंने सरोगेट प्राथमिक कुंजी केserial रूप में कॉलम जोड़े । Postgres 10 में या बाद में इसके बजाय एक कॉलम पर विचार करें । देख:IDENTITY

    मैं अत्यधिक सलाह देता हूं कि, क्योंकि एक उत्पाद का नाम शायद ही अनूठा है (एक अच्छा "प्राकृतिक कुंजी" नहीं)। इसके अलावा, विशिष्टता को लागू करने और विदेशी कुंजी में स्तंभ को संदर्भित आम तौर पर एक 4-बाइट के साथ सस्ता है integer(या यहां तक कि एक 8 बाइट bigintएक स्ट्रिंग के रूप में जमा के साथ तुलना में) textया varchar

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

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

  • priceकी है डेटा प्रकार numeric आंशिक संख्या स्टोर करने के लिए ठीक के रूप में दर्ज (चल बिन्दु प्रकार के बजाय मनमाने ढंग से सटीक प्रकार)। यदि आप विशेष रूप से पूरे नंबरों से निपटते हैं, तो वह बनाएं integer। उदाहरण के लिए, आप सेंट के रूप में कीमतों को बचा सकते हैं ।

  • amount( "Products"अपने प्रश्न में) जोड़ने तालिका में चला जाता है bill_productऔर इस प्रकार का है numericऔर साथ ही। फिर, integerयदि आप विशेष रूप से पूरे नंबरों से निपटते हैं।

  • आप विदेशी कुंजियों को देखते हैं bill_product? मैंने दोनों को कैस्केड परिवर्तनों के लिए बनाया ON UPDATE CASCADE:। यदि एक को बदलना चाहिए product_idया bill_idबदलना चाहिए, तो सभी प्रविष्टियों के आधार पर परिवर्तन को रोक दिया bill_productजाता है और कुछ भी नहीं टूटता है। वे केवल अपने स्वयं के महत्व के बिना संदर्भ हैं।
    मैंने इसके ON DELETE CASCADEलिए भी उपयोग किया bill_id: यदि कोई बिल नष्ट हो जाता है, तो इसके विवरण इसके साथ मर जाते हैं।
    उत्पादों के लिए ऐसा नहीं है: आप बिल में उपयोग किए जाने वाले उत्पाद को हटाना नहीं चाहते हैं। यदि आप यह प्रयास करते हैं तो पोस्टग्रैज एक त्रुटि फेंक देंगे। आप productइसके बजाय अप्रचलित पंक्तियों ("सॉफ्ट-डिलीट") को चिह्नित करने के लिए एक और कॉलम जोड़ेंगे ।

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

  • अध्याय को CREATE TABLEमैनुअल में पढ़ें ।

  • प्राथमिक कुंजी कुंजी स्तंभों पर एक अद्वितीय सूचकांक के साथ कार्यान्वित की जाती है , जो पीके स्तंभ (ओं) पर शर्तों के साथ तेज़ी से प्रश्न बनाती है। हालाँकि, कुंजी कॉलम का अनुक्रम बहुरंगी कुंजी में प्रासंगिक है। चूँकि मेरे उदाहरण में PK चालू bill_productहै (bill_id, product_id), आप किसी अन्य इंडेक्स को जोड़ना चाह सकते हैं product_idया (product_id, bill_id)यदि आपके पास दिए गए प्रश्नों की तलाश है product_idऔर नहीं bill_id। देख:

  • मैनुअल में अनुक्रमित पर अध्याय पढ़ें ।


मैं मानचित्रण तालिका के लिए एक सूचकांक कैसे बना सकता हूं bill_product? आम तौर पर यह दिखना चाहिए CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id):। क्या यह सही है?
कोड़ीलाइन

1
@ कोडीलाइन: यह सूचकांक पीके द्वारा स्वचालित रूप से बनाया जाता है।
इरविन ब्रान्डेसटेटर

1
@ErwinBrandstetter: product_id कॉलम के लिए बिल_प्रोडक्ट पर एक इंडेक्स नहीं बनाया जाना चाहिए?
क्रिश्चियन

2
@ ChristianB.Almeida: यह कई मामलों में उपयोगी है, हाँ। मैंने अनुक्रमण के बारे में थोड़ा जोड़ा।
एरविन ब्रान्डसेट्टर 20

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