शून्य-या-एक-शून्य-या-एक


9

मैं शून्य-या-एक-शून्य-या-एक-संबंध Sql सर्वर में सबसे प्राकृतिक तरीके से कैसे मॉडल करूं?

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

नीचे सबसे अच्छा मैं के बारे में सोच सकता है:

CREATE TABLE [dbo].[Hazard](
  [HazardId] [int] IDENTITY(1,1) NOT NULL,
  [TaskId] [int] NULL,
  [Details] [varchar](max) NULL,
 CONSTRAINT [PK_Hazard] PRIMARY KEY CLUSTERED 
(
  [HazardId] ASC
))

GO

ALTER TABLE [dbo].[Hazard]  WITH CHECK ADD  CONSTRAINT [FK_Hazard_Task] FOREIGN KEY([TaskId])
REFERENCES [dbo].[Task] ([TaskId])
GO


CREATE TABLE [dbo].[Task](
  [TaskId] [int] IDENTITY(1,1) NOT NULL,
  [HazardId] [int] NULL,
  [Details] [varchar](max) NULL,
 CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED 
(
  [TaskId] ASC
))

GO

ALTER TABLE [dbo].[Task]  WITH CHECK ADD  CONSTRAINT [FK_Task_Hazard] FOREIGN KEY([HazardId])
REFERENCES [dbo].[Hazard] ([HazardId])
GO

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

क्या कोई बेहतर तरीका है?

यहां छवि विवरण दर्ज करें


क्या कोई कारण है कि आप हेज़र्ड टेबल पर टास्किड पर एक अद्वितीय सूचकांक और टास्क टेबल पर हज़ार्डिड का एक अद्वितीय सूचकांक नहीं बना सकते हैं? इससे ऐसा होगा कि आप उनमें से केवल एक को तालिका में रख सकते हैं, जो मुझे लगता है कि आप क्या हासिल करना चाहते हैं।
मॉस्कनर

@mskinner लेकिन वे अद्वितीय नहीं हैं, उनमें से कई हो सकते हैं null
एंड्रयू साविनिख

आह, गच्चा। उस स्थिति में, श्री बेन-गान ने यह लिखने के लिए एक शानदार लिखा है कि कैसे उस अवरोध को बनाने के लिए यहाँ कई नल की अनुमति है sqlmag.com/sql-server-2008/unique-constraint-multiple-nulls । मुझे लगता है कि यह आपके लिए काम करेगा। मुझे पता है अगर नहीं।
mskinner

इसके लिए एक साइड नोट के रूप में, फ़िल्टर किए गए इंडेक्स का उपयोग करके कई समस्याएं हैं, इसलिए यदि आप परिचित नहीं हैं, तो यह संभवतः उन पर पढ़ने लायक होगा। यहाँ उस पर एक अच्छा ब्लॉग है। blogs.msdn.com/b/sqlprogrammability/archive/2009/06/29/… , लेकिन इस विशिष्ट परिदृश्य के लिए, यह आपके लिए अच्छी तरह से काम कर सकता है, यह मानते हुए कि अन्य मुद्दे आपको बहुत दुःख नहीं पहुँचाते हैं
मॉस्किनर

FWIW एक अद्वितीय फ़िल्टर किए गए सूचकांक केवल गैर-अशक्त पंक्तियों में विशिष्टता लागू कर सकते हैं, जैसेCREATE UNIQUE INDEX x ON dbo.Hazards(TaskID) WHERE TaskID IS NOT NULL;
हारून बर्ट्रेंड

जवाबों:


9

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

तो, यह इस तरह होगा:

CREATE TABLE dbo.Hazard
(
  HazardId int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Hazard PRIMARY KEY CLUSTERED,
  Details varchar(max) NULL
);

CREATE TABLE dbo.Task
(
  TaskId int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Task PRIMARY KEY CLUSTERED,
  Details varchar(max) NULL,
);

CREATE TABLE dbo.HazardTask
(
  HazardId int NOT NULL
    CONSTRAINT FK_HazardTask_Hazard FOREIGN KEY REFERENCES dbo.Hazard (HazardId)
    CONSTRAINT UQ_HazardTask_Hazard UNIQUE,
  TaskId int NOT NULL
    CONSTRAINT FK_HazardTask_Task FOREIGN KEY REFERENCES dbo.Task (TaskId)
    CONSTRAINT UQ_HazardTask_Task UNIQUE
);

(HazardId, TaskId)यदि आप किसी अन्य तालिका से इन संयोजनों को संदर्भित करना चाहते हैं, तो आप इसके अतिरिक्त प्राथमिक कुंजी घोषित कर सकते हैं । जोड़े को अद्वितीय रखने के उद्देश्य से, हालांकि, प्राथमिक कुंजी अनावश्यक है, यह पर्याप्त है कि प्रत्येक आईडी अद्वितीय है।


1
+1 मुझे लगता है कि इस तरह के संबंध को लागू करने का यह सबसे स्वाभाविक तरीका है। लेकिन सामान्य तौर पर कोई भी एक टपल को प्राथमिक के रूप में चुनता है, यदि यह न्यूनतम हो तो टपल (HazardId, TaskId)में टपल होते हैं (HazardId)और (TaskId)दोनों ही इस तालिका की एक पंक्ति को विशिष्ट रूप से पहचानते हैं। उनमें से एक को प्राथमिक कुंजी के रूप में चुना जाना चाहिए।
चमत्कार 173

2

सारांश में:

  • खतरों में एक या शून्य कार्य हैं
  • कार्य में एक या शून्य खतरे हैं

यदि टास्क और हेज़र्ड टेबल का उपयोग किसी और चीज़ के लिए किया जाता है (यानी कार्यों और / या खतरों में अन्य डेटा जुड़े हैं, और आपने जो मॉडल हमें दिखाया है, वह केवल संबंधित फ़ील्ड दिखाने के लिए सरल है) मैं कहूंगा कि आपका समाधान सही है।

अन्यथा, यदि कार्य और खतरे केवल एक-दूसरे से जोड़े जाते हैं, तो आपको दो तालिकाओं की आवश्यकता नहीं है; आप निम्नलिखित क्षेत्रों के साथ, उनके संबंधों के लिए एक एकल तालिका बना सकते हैं:

ID            int, PK
TaskID        int, (filtered) unique index  
TaskDetails   varchar
HazardID      int, (filtered) unique index
HazardDetails varchar

1
मैंने स्पष्ट करने की स्वतंत्रता ली कि यह प्रत्येक मामले में एक फ़िल्टर किया गया सूचकांक होना चाहिए, (हालांकि यह समस्या के विवरण से अनुमान लगाया जा सकता है, यह पूरी तरह से स्पष्ट नहीं लग सकता है)। कृपया बेझिझक आगे संपादित करें यदि आपको लगता है कि अनावश्यक है या एक अलग तरीके से विचार व्यक्त करना चाहते हैं।
एंड्री एम

मुझे कहना चाहिए कि मैं अभी भी इस विचार से खुश नहीं हूं। मुद्दा यह है कि मुझे मैन्युअल रूप से टास्कआईडी और हैज़र्डआईडी जनरेट करना होगा। यदि यह 2012 था, तो उसके लिए दृश्यों का उपयोग करना संभव होगा, लेकिन तब भी यह मुझे सही नहीं लगेगा। मुझे लगता है कि यह इसलिए है क्योंकि दो चीजें, कार्य और खतरे, पूरी तरह से अलग संस्थाएं हैं और इसलिए उन्हें एक ही तालिका में संग्रहीत करने के विचार के साथ सामंजस्य करना कठिन है।
एंड्री एम

इस डिजाइन चुन लिया जाता है, तो हम क्यों की क्या ज़रूरत है TaskIDऔर HazardID? आपके पास 2 बीआईटी कॉलम हो सकते हैं IsTask, IsHazardऔर एक बाधा यह है कि दोनों झूठे नहीं हैं। फिर Hazardतालिका केवल एक दृश्य है: CRAETE VIEW Hazard SELECT HazardID = ID, HazardDetails, ... FROM ThisTable WHERE IsHazard = 1;और कार्य क्रमशः।
ypercube y

@ypercube आप तालिका में एक आकारहीन चीज़ का भंडारण करेंगे और फिर बाइनरी फ़ील्ड का उपयोग करके यह बताएंगे कि यह कार्य है या कोई खतरा। यह बदसूरत डेटाबेस मॉडलिंग है।
dr_

@AndriyM मैं समझता हूं, और मैं इस बात से सहमत हूं कि, ज्यादातर मामलों में , हमें एक ही तालिका में दो प्रकार की विभिन्न संस्थाओं को संग्रहीत नहीं करना चाहिए। हालांकि, मेरे कैविएट को पढ़ें: यदि टास्क और खतरों 1-टू -1 रिश्ते में हैं और केवल इसके लिए मौजूद हैं , तो यह एक ही तालिका का उपयोग करने के लिए स्वीकार्य है।
dr_

1

एक अन्य दृष्टिकोण जो अभी तक उल्लेख नहीं किया गया है, वह यह है कि खतरों और कार्य एक ही आईडी स्थान का उपयोग करते हैं। अगर किसी हाजर्ड के पास टास्क है, तो उसके पास एक ही आईडी होगी। अगर कोई टास्क किसी हज़ार्ड के लिए है तो उसके पास एक ही आईडी होगी।

आप इन आईडी को पॉप्युलेट करने के लिए पहचान कॉलम के बजाय एक अनुक्रम का उपयोग करेंगे।

इस प्रकार के डेटा मॉडल पर क्वेरी अपने परिणामों को प्राप्त करने के लिए (पूर्ण) बाहरी जोड़ का उपयोग करेगी।

यह दृष्टिकोण @ AndriyM के जवाब से बहुत मिलता-जुलता है, सिवाय इसके कि उसका जवाब आईडी अलग होने की अनुमति देता है, और इस रिश्ते को संग्रहीत करने के लिए एक तालिका।

मुझे यकीन नहीं है कि आप दो-तालिका परिदृश्य के लिए इस दृष्टिकोण का उपयोग करना चाहते हैं, लेकिन जब तालिकाओं की संख्या बढ़ जाती है तो यह अच्छी तरह से काम करता है।


योगदान देने के लिए धन्यवाद, मैंने उस दृष्टिकोण पर भी विचार किया है। मैं अंत में इसके खिलाफ फैसला किया क्योंकि अनुक्रम sql2008 में लागू करने के लिए अजीब है और इससे अधिक परेशानी की बात है कि मैं इसके साथ तैयार होना चाहता हूं।
एंड्रयू साविनिख
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.