22

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

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

मान लें कि आप कुछ ऐसी जानकारी भी स्टोर करना चाहते हैं जो सीधे परीक्षण से संबंधित नहीं हैं (जैसे कि परीक्षण की गई चीज़ के डिजाइनर की कर्मचारी आईडी)। ये कॉलम "टेस्ट" टेबल में बिल्कुल सही नहीं लगते हैं, खासकर क्योंकि उन्हें उसी वाहन पर सभी परीक्षणों के लिए दोहराया जाएगा।

मुझे टेबल की एक संभावित व्यवस्था को चित्रित करने दें, ताकि आप शामिल प्रश्न देख सकें।

 
Speedboats 
id | col_about_speedboats_but_not_tests1 | col_about_speedboats_but_not_tests2 

Cars 
id | col_about_cars_but_not_tests1 | col_about_cars_but_not_tests2 

Gokarts 
id | col_about_gokarts_but_not_tests1 | col_about_gokarts_but_not_tests2 

Tests 
id | type | id_in_type | col_about_all_tests1 | col_about_all_tests2 
(id_in_type will refer to the id column of one of the next three tables, 
depending on the value of type) 

SpeedboatTests 
id | speedboat_id | col_about_speedboat_tests1 | col_about_speedboat_tests2 

CarTests 
id | car_id | col_about_car_tests1 | col_about_car_tests2 

GokartTests 
id | gokart_id | col_about_gokart_tests1 | col_about_gokart_tests2 

इस संरचना के बारे में अच्छा/बुरा क्या है और इस तरह कुछ लागू करने का पसंदीदा तरीका क्या होगा?

क्या होगा यदि कोई ऐसी जानकारी भी है जो वाहन वाहन में आपके पास आने वाले सभी वाहनों पर लागू होती है? क्या कारटेस्ट टेबल तब कुछ दिखेंगे ...

 
id | vehicle_id | ... 

With a Vehicles table like this: 
id | type | id_in_type 
(with id_in_type pointing to the id of either a speedboat, car, or go-kart) 

यह ऐसा लगता है कि यह शाही गड़बड़ हो रहा है। इस तरह कुछ कैसे स्थापित किया जाना चाहिए?

+0

संभावित डुप्लिकेट [आप डेटाबेस में विरासत को प्रभावी तरीके से कैसे मॉडल करते हैं?] (Http://stackoverflow.com/questions/190296/how-do-you-effectively-model-inheritance-in-a-डेटाबेस) – Musa

उत्तर

37

type और id_in_type डिज़ाइन को Polymorphic Associations कहा जाता है। यह डिज़ाइन कई तरीकों से सामान्यीकरण के नियमों को तोड़ देता है। यदि कुछ और नहीं है, तो यह एक लाल झंडा होना चाहिए कि आप वास्तविक विदेशी कुंजी बाधा घोषित नहीं कर सकते हैं, क्योंकि id_in_type कई तालिकाओं का संदर्भ दे सकता है।

  • एक सार तालिका Vehicles बनाओ सभी वाहन उप-प्रकारों और वाहन के परीक्षण के लिए एक सार संदर्भ बिंदु प्रदान करने के लिए:

    यहाँ अपने तालिकाओं को परिभाषित करने का एक बेहतर तरीका है।

  • प्रत्येक वाहन उप-प्रकार में प्राथमिक कुंजी होती है जो स्वत: वृद्धि नहीं करती है, बल्कि इसके बजाय Vehicles संदर्भित करती है।
  • प्रत्येक परीक्षण उप-प्रकार में प्राथमिक कुंजी होती है जो स्वत: वृद्धि नहीं करती है, बल्कि इसके बजाय Tests संदर्भित करती है।
  • प्रत्येक परीक्षण उप-प्रकार में संबंधित वाहन उप-प्रकार के लिए एक विदेशी कुंजी भी होती है।

यहाँ नमूना DDL है:

CREATE TABLE Vehicles (
vehicle_id INT AUTO_INCREMENT PRIMARY KEY 
); 

CREATE TABLE Speedboats (
vehicle_id INT PRIMARY KEY, 
col_about_speedboats_but_not_tests1 INT, 
col_about_speedboats_but_not_tests2 INT, 
FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id) 
); 

CREATE TABLE Cars (
vehicle_id INT PRIMARY KEY, 
col_about_cars_but_not_tests1 INT, 
col_about_cars_but_not_tests2 INT, 
FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id) 
); 

CREATE TABLE Gokarts (
vehicle_id INT PRIMARY KEY, 
col_about_gokarts_but_not_tests1 INT, 
col_about_gokarts_but_not_tests2 INT, 
FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id) 
); 

CREATE TABLE Tests (
test_id INT AUTO_INCREMENT PRIMARY KEY, 
col_about_all_tests1 INT, 
col_about_all_tests2 INT 
); 

CREATE TABLE SpeedboatTests (
test_id INT PRIMARY KEY, 
vehicle_id INT NOT NULL, 
col_about_speedboat_tests1 INT, 
col_about_speedboat_tests2 INT, 
FOREIGN KEY(test_id) REFERENCES Tests(test_id), 
FOREIGN KEY(vehicle_id) REFERENCES Speedboats(vehicle_id) 
); 

CREATE TABLE CarTests (
test_id INT PRIMARY KEY, 
vehicle_id INT NOT NULL, 
col_about_car_tests1 INT, 
col_about_car_tests2 INT, 
FOREIGN KEY(test_id) REFERENCES Tests(test_id), 
FOREIGN KEY(vehicle_id) REFERENCES Cars(vehicle_id) 
); 

CREATE TABLE GokartTests (
test_id INT PRIMARY KEY, 
vehicle_id INT NOT NULL, 
col_about_gokart_tests1 INT, 
col_about_gokart_tests2 INT, 
FOREIGN KEY(test_id) REFERENCES Tests(test_id), 
FOREIGN KEY(vehicle_id) REFERENCES Gokarts(vehicle_id) 
); 

आप वैकल्पिक रूप से घोषित कर सकता है Tests.vehicle_id जो Vehicles.vehicle_id का संदर्भ और प्रत्येक परीक्षा उप-प्रकार तालिका में vehicle_id विदेशी कुंजी से छुटकारा पाने के लिए, लेकिन यह है कि इस तरह के एक के रूप में विसंगतियों की अनुमति होगी स्पीडबोट परीक्षण जो एक गोकर्ट की आईडी का संदर्भ देता है।

+0

यह बेहद सहायक और पूरी तरह से था। धन्यवाद! –

+2

इस सब को छोड़कर अन्य सभी उत्तरों और, शायद, [मार्टिन फाउलर का उल्लेख करने वाला] [http://stackoverflow.com/a/554552/279564), हटाया जाना चाहिए या विस्मरण में दफनाया जाना चाहिए ... ओएमजी .. – Rafa

+0

धन्यवाद @ राफा! चीयर्स –

0

मैं इसे विभिन्न तालिकाओं में तोड़ दूंगा, उदा। वाहन (आईडी, प्रकार, आदि) वाहन सामग्री() वाहन आईडी, विशेषता आईडी, मूल्य), क्रैशटेस्टइन्फो (वाहन आईडी, क्रैशटेस्ट, दिनांक इत्यादि) क्रैशटेस्ट एट्रिब्यूट्स (क्रैशटेस्ट आईडी, एट्रिब्यूटिड, वैल्यू)

या प्रत्येक सेट के लिए अलग-अलग टेबल समान विवरण के बारे में जो दर्ज किया जाना चाहिए।

+0

यह एंटिटी-एट्रिब्यूट-वैल्यू डिज़ाइन है, जो ओपी के परिदृश्य के लिए अधिक है। –

14

डाटाबेस टेबल पर विरासत पदानुक्रमों को मैप करने के लिए, मुझे लगता है कि मार्टिन फाउलर अपनी पुस्तक पैटर्न ऑफ़ एंटरप्राइज़ एप्लिकेशन आर्किटेक्चर में विकल्पों को काफी अच्छी तरह से बताता है।

http://martinfowler.com/eaaCatalog/singleTableInheritance.html

http://martinfowler.com/eaaCatalog/classTableInheritance.html

http://martinfowler.com/eaaCatalog/concreteTableInheritance.html

अतिरिक्त फ़ील्ड/स्तंभों की संख्या उपवर्गों के लिए छोटा है, तो एकल तालिका भाग आमतौर पर सबसे आसान से निपटने के लिए है।

आप अपने डेटाबेस के लिए PostgreSQL का उपयोग कर रहे हैं और आप एक डेटाबेस विशिष्ट सुविधा के लिए अपने आप को टाई करने को तैयार हैं तो उसे सीधे तालिका विरासत का समर्थन करता है:

http://www.postgresql.org/docs/8.3/static/ddl-inherit.html

+0

मैं मूल प्रश्न में उल्लिखित शाही गड़बड़ी के विशिष्ट संदर्भ के साथ जोड़ता हूं कि विदेशी कुंजी विशिष्ट वाहन प्रकार से सार वाहन तालिका में इंगित करेगी। यानी स्पीडबोट (vehicle_id एफके, speedboat_specific_column1, आदि ...) – Robin

-3

आपका डिजाइन उचित है और पीछा कर रहा है सही सामान्यीकरण नियम। हो सकता है कि आप एक वाहन आईडी और टाइप (यानी स्पीडबोट्स, कारों और गोकर्ट्स के लिए "पैरेंट" के साथ एक वाहन तालिका खो रहे हों ... जहां आप "DesignByUserId" जैसी सामग्री रखेंगे)।वाहन तालिका और स्पीडबोट टेबल के बीच एक-से-एक संबंध है, और वाहन और स्पीडबोट/कार/गोकार्ट्स के बीच एक 1-और-केवल-1 संबंध है (यानी वाहन में केवल स्पीडबोट के लिए 1 रिकॉर्ड हो सकता है, कारें या कार्ट्स जाएं) ... हालांकि अधिकांश डीबी इस के लिए एक आसान प्रवर्तन तंत्र प्रदान नहीं करते हैं।

एक सामान्यीकरण नियम जो इन प्रकार की चीजों की पहचान करने में मदद करता है यह है कि एक फ़ील्ड केवल तालिका की प्राथमिक कुंजी पर निर्भर होना चाहिए। एक समेकित तालिका में जहां स्पीडबोट, कार, और गोकर्ट परीक्षण के परिणाम एक साथ संग्रहीत होते हैं तो कार संबंधित क्षेत्र न केवल परीक्षण की तारीख पर निर्भर करते हैं बल्कि वेचिकल आईडी और वाहन प्रकार पर भी निर्भर करते हैं। परीक्षण परिणाम तालिका के लिए प्राथमिक कुंजी परीक्षण तिथि + वाहन आईडी है, और वाहन का प्रकार परीक्षण डेटा पंक्ति अद्वितीय नहीं बनाता है (यानि 01/01/200912: 30:00 बजे एक विशिष्ट वाहन पर परीक्षण करने के लिए वैसे भी है वह एक स्पीडबोट और कार दोनों है ... नहीं ... नहीं किया जा सकता है)।

मैं सामान्य रूप से सामान्यीकरण नियम को समझा नहीं रहा हूं ... लेकिन जब मैं औपचारिक विवरण पढ़ता हूं तो तीसरा/चौथा/5 वां सामान्य रूप नियम मुझे हमेशा भ्रमित करता है। उनमें से एक (तीसरा/चौथा/5 वां) प्राथमिक कुंजी और केवल प्राथमिक कुंजी के आधार पर फ़ील्ड के साथ सौदा करता है। नियम यह धारणा करता है कि प्राथमिक कुंजी को सही ढंग से पहचाना गया है (गलत कुंजी प्राथमिक कुंजी कुंजी करना बहुत आसान है)।

+1

-1 क्योंकि पॉलिमॉर्फिक एसोसिएशन डिज़ाइन ('टाइप' और 'id_in_type' चीज़) * सामान्य * डिज़ाइन नहीं है। –

+0

उहम्म ... http://en.wikipedia.org/wiki/Fourth_normal_form देखें। पिज्जा उदाहरण काफी उचित है। – user53794

+1

आप कह रहे हैं {test_id, type} -> -> {id_in_type} 4 एनएफ पास करता है, इसलिए {test_id, type} एक सुपरकी है? मैं एक संबंध की मूल परिभाषा के बारे में बात कर रहा हूं, जिसमें प्रत्येक विशेषता एक "चीज़" के लिए एक मान का प्रतिनिधित्व करती है - लेकिन id_in_type तीन अलग-अलग प्रकार की चीजें हैं। –

0

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

सर्वोत्तम लेख, आईएमओ, ईआर मॉडलिंग के संदर्भ में जीन-स्पेक पर चर्चा करते हैं। यदि आप जानते हैं कि एक ईआर मॉडल को एक रिलेशनल मॉडल में कैसे अनुवादित किया जाए, और वहां से SQL टेबल तक, तो आपको पता चलेगा कि एक बार जब वे आपको ईआर में जेन-स्पेक मॉडल कैसे मॉडल करते हैं तो क्या करना है।

यदि आप केवल "जेन-स्पेक" पर Google हैं, तो आप जो कुछ देखेंगे वह ऑब्जेक्ट उन्मुख है, न कि रिलेशनल उन्मुख। यह सामान तब भी उपयोगी हो सकता है, जब तक कि आप ऑब्जेक्ट रिलेशनल प्रतिबाधा विसंगति को दूर करने के बारे में जानते हों।

+2

यदि आप कुछ सीधा लिंक प्रदान कर सकते हैं तो बहुत अच्छा होगा। – JamesC

+0

यह केवल कक्षा तालिका दृष्टिकोण है (जैसा कि स्वीकृत उत्तर में संदर्भित है, और एक संदर्भ फाउलर) – oligofren

0

यदि आप SQLAlchemy का उपयोग कर रहे हैं, तो पाइथन के लिए ऑब्जेक्ट-रिलेशनल मैपर, आप configure how inheritance hierarchies are mapped to database tables कर सकते हैं। ऑब्जेक्ट-रिलेशनल मैपर अन्यथा थकाऊ एसक्यूएल को टम करने के लिए अच्छे हैं।

आपकी समस्या लंबवत तालिकाओं के लिए उपयुक्त हो सकती है। स्कीमा में सब कुछ संग्रहीत करने के बजाय, ऑब्जेक्ट के प्रकार और प्राथमिक कुंजी को एक तालिका में और किसी अन्य तालिका में प्रत्येक ऑब्जेक्ट के लिए कुंजी/मान tuples संग्रहीत करें। यदि आप वास्तव में कार परीक्षण संग्रहित कर रहे थे, तो यह सेटअप नए प्रकार के परिणामों को जोड़ने में अधिक आसान बना देगा।

संबंधित मुद्दे