आप जो वर्णन कर रहे हैं उसे पॉलिमॉर्फिक एसोसिएशन कहा जाता है। यही है, "विदेशी कुंजी" कॉलम में एक आईडी मान होता है जो लक्ष्य तालिकाओं के सेट में से एक में मौजूद होना चाहिए। आमतौर पर लक्ष्य तालिकाएँ किसी न किसी तरह से संबंधित होती हैं, जैसे डेटा के कुछ सामान्य सुपरक्लास के उदाहरण। आपको विदेशी कुंजी कॉलम के साथ एक और कॉलम की भी आवश्यकता होगी, ताकि प्रत्येक पंक्ति पर, आप निर्दिष्ट कर सकें कि कौन सी लक्ष्य तालिका संदर्भित है।
CREATE TABLE popular_places (
user_id INT NOT NULL,
place_id INT NOT NULL,
place_type VARCHAR(10) -- either 'states' or 'countries'
-- foreign key is not possible
);
SQL बाधाओं का उपयोग करके पॉलिमॉर्फिक संघों को मॉडल करने का कोई तरीका नहीं है। एक विदेशी कुंजी बाधा हमेशा एक . का संदर्भ देती है लक्ष्य तालिका।
पॉलिमॉर्फिक एसोसिएशन रेल और हाइबरनेट जैसे ढांचे द्वारा समर्थित हैं। लेकिन वे स्पष्ट रूप से कहते हैं कि आपको इस सुविधा का उपयोग करने के लिए SQL बाधाओं को अक्षम करना होगा। इसके बजाय, यह सुनिश्चित करने के लिए कि संदर्भ संतुष्ट है, एप्लिकेशन या फ्रेमवर्क को समान कार्य करना चाहिए। यही है, विदेशी कुंजी में मान संभावित लक्ष्य तालिकाओं में से एक में मौजूद है।
डेटाबेस संगतता को लागू करने के संबंध में पॉलिमॉर्फिक एसोसिएशन कमजोर हैं। डेटा अखंडता उन सभी क्लाइंट पर निर्भर करती है जो लागू किए गए समान संदर्भात्मक अखंडता तर्क के साथ डेटाबेस तक पहुंचते हैं, और साथ ही प्रवर्तन बग-मुक्त होना चाहिए।
यहां कुछ वैकल्पिक समाधान दिए गए हैं जो डेटाबेस-प्रवर्तित संदर्भात्मक अखंडता का लाभ उठाते हैं:
प्रति लक्ष्य एक अतिरिक्त तालिका बनाएं। उदाहरण के लिए popular_states
और popular_countries
, जो संदर्भ states
और countries
क्रमश। इनमें से प्रत्येक "लोकप्रिय" तालिका उपयोगकर्ता की प्रोफ़ाइल को भी संदर्भित करती है।
CREATE TABLE popular_states (
state_id INT NOT NULL,
user_id INT NOT NULL,
PRIMARY KEY(state_id, user_id),
FOREIGN KEY (state_id) REFERENCES states(state_id),
FOREIGN KEY (user_id) REFERENCES users(user_id),
);
CREATE TABLE popular_countries (
country_id INT NOT NULL,
user_id INT NOT NULL,
PRIMARY KEY(country_id, user_id),
FOREIGN KEY (country_id) REFERENCES countries(country_id),
FOREIGN KEY (user_id) REFERENCES users(user_id),
);
इसका मतलब यह है कि उपयोगकर्ता के सभी लोकप्रिय पसंदीदा स्थानों को प्राप्त करने के लिए आपको इन दोनों तालिकाओं को क्वेरी करने की आवश्यकता है। लेकिन इसका मतलब है कि आप निरंतरता को लागू करने के लिए डेटाबेस पर भरोसा कर सकते हैं।
एक places
टेबल एक सुपरटेबल के रूप में। जैसा कि एबी ने उल्लेख किया है, दूसरा विकल्प यह है कि आपके लोकप्रिय स्थान places
. जैसी तालिका का संदर्भ देते हैं , जो दोनों states
. का अभिभावक है और countries
. अर्थात्, दोनों राज्यों और देशों के पास places
. के लिए एक विदेशी कुंजी भी है (आप इस विदेशी कुंजी को states
. की प्राथमिक कुंजी भी बना सकते हैं और countries
)।
CREATE TABLE popular_areas (
user_id INT NOT NULL,
place_id INT NOT NULL,
PRIMARY KEY (user_id, place_id),
FOREIGN KEY (place_id) REFERENCES places(place_id)
);
CREATE TABLE states (
state_id INT NOT NULL PRIMARY KEY,
FOREIGN KEY (state_id) REFERENCES places(place_id)
);
CREATE TABLE countries (
country_id INT NOT NULL PRIMARY KEY,
FOREIGN KEY (country_id) REFERENCES places(place_id)
);
दो स्तंभों का उपयोग करें। एक स्तंभ के बजाय जो दो लक्ष्य तालिकाओं में से किसी एक को संदर्भित कर सकता है, दो स्तंभों का उपयोग करें। ये दो कॉलम NULL
. हो सकते हैं; वास्तव में उनमें से केवल एक गैर-NULL
होना चाहिए ।
CREATE TABLE popular_areas (
place_id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
state_id INT,
country_id INT,
CONSTRAINT UNIQUE (user_id, state_id, country_id), -- UNIQUE permits NULLs
CONSTRAINT CHECK (state_id IS NOT NULL OR country_id IS NOT NULL),
FOREIGN KEY (state_id) REFERENCES places(place_id),
FOREIGN KEY (country_id) REFERENCES places(place_id)
);
संबंधपरक सिद्धांत के संदर्भ में, बहुरूपी संघ प्रथम सामान्य प्रपत्र
का उल्लंघन करते हैं , क्योंकि popular_place_id
वास्तव में दो अर्थों वाला एक स्तंभ है:यह या तो एक राज्य या एक देश है। आप किसी व्यक्ति की age
संग्रहित नहीं करेंगे और उनका phone_number
एक ही कॉलम में, और इसी कारण से आपको state_id
. दोनों को स्टोर नहीं करना चाहिए और country_id
एक ही कॉलम में। तथ्य यह है कि इन दो विशेषताओं में संगत डेटा प्रकार हैं संयोग है; वे अभी भी विभिन्न तार्किक संस्थाओं को दर्शाते हैं।
बहुरूपी संघ तीसरे सामान्य फ़ॉर्म का भी उल्लंघन करते हैं , क्योंकि कॉलम का अर्थ अतिरिक्त कॉलम पर निर्भर करता है जो उस तालिका को नाम देता है जिससे विदेशी कुंजी संदर्भित होती है। तीसरे सामान्य रूप में, किसी तालिका में एक विशेषता केवल उस तालिका की प्राथमिक कुंजी पर निर्भर होनी चाहिए।
@SavasVedova से दोबारा टिप्पणी करें:
मुझे यकीन नहीं है कि मैं तालिका परिभाषाओं या उदाहरण क्वेरी को देखे बिना आपके विवरण का पालन करता हूं, लेकिन ऐसा लगता है कि आपके पास बस एक से अधिक Filters
हैं टेबल, प्रत्येक में एक विदेशी कुंजी होती है जो एक केंद्रीय Products
. का संदर्भ देती है टेबल।
CREATE TABLE Products (
product_id INT PRIMARY KEY
);
CREATE TABLE FiltersType1 (
filter_id INT PRIMARY KEY,
product_id INT NOT NULL,
FOREIGN KEY (product_id) REFERENCES Products(product_id)
);
CREATE TABLE FiltersType2 (
filter_id INT PRIMARY KEY,
product_id INT NOT NULL,
FOREIGN KEY (product_id) REFERENCES Products(product_id)
);
...and other filter tables...
उत्पादों को एक विशिष्ट प्रकार के फ़िल्टर से जोड़ना आसान है यदि आप जानते हैं कि आप किस प्रकार से जुड़ना चाहते हैं:
SELECT * FROM Products
INNER JOIN FiltersType2 USING (product_id)
यदि आप चाहते हैं कि फ़िल्टर प्रकार गतिशील हो, तो आपको SQL क्वेरी बनाने के लिए एप्लिकेशन कोड लिखना होगा। SQL के लिए आवश्यक है कि जब आप क्वेरी लिखें तो तालिका निर्दिष्ट और स्थिर हो। Products
की अलग-अलग पंक्तियों में पाए गए मानों के आधार पर आप सम्मिलित तालिका को गतिशील रूप से नहीं चुन सकते ।
सभी . में शामिल होने का एकमात्र अन्य विकल्प है बाहरी जॉइन का उपयोग करके तालिकाओं को फ़िल्टर करें। जिनके पास कोई मेल खाने वाला product_id नहीं है, उन्हें केवल नल की एक पंक्ति के रूप में वापस कर दिया जाएगा। लेकिन आपको अभी भी सभी को हार्डकोड करना होगा सम्मिलित तालिकाएँ, और यदि आप नई फ़िल्टर तालिकाएँ जोड़ते हैं, तो आपको अपना कोड अपडेट करना होगा।
SELECT * FROM Products
LEFT OUTER JOIN FiltersType1 USING (product_id)
LEFT OUTER JOIN FiltersType2 USING (product_id)
LEFT OUTER JOIN FiltersType3 USING (product_id)
...
सभी फ़िल्टर तालिकाओं में शामिल होने का दूसरा तरीका इसे क्रमानुसार करना है:
SELECT * FROM Product
INNER JOIN FiltersType1 USING (product_id)
UNION ALL
SELECT * FROM Products
INNER JOIN FiltersType2 USING (product_id)
UNION ALL
SELECT * FROM Products
INNER JOIN FiltersType3 USING (product_id)
...
लेकिन इस प्रारूप में अभी भी आपको सभी तालिकाओं के संदर्भ लिखने की आवश्यकता है। इसके आसपास कोई नहीं है।