क्या सर्कुलर फॉरेन की के संदर्भों को स्वीकार करना स्वीकार्य है \ _ उनसे कैसे बचें?


29

क्या विदेशी कुंजी क्षेत्र पर दो तालिकाओं के बीच एक परिपत्र संदर्भ होना स्वीकार्य है?

यदि नहीं, तो इन स्थितियों से कैसे बचा जा सकता है?

यदि हां, तो डेटा कैसे डाला जा सकता है?

नीचे एक उदाहरण है जहां (मेरी राय में) एक परिपत्र संदर्भ स्वीकार्य होगा:

CREATE TABLE Account
(
    ID INT PRIMARY KEY IDENTITY,
    Name VARCHAR(50)
)

CREATE TABLE Contact
(
    ID INT PRIMARY KEY IDENTITY,
    Name VARCHAR(50),
    AccountID INT FOREIGN KEY REFERENCES Account(ID)
)

ALTER TABLE Account ADD PrimaryContactID INT FOREIGN KEY REFERENCES Contact(ID)

2
" यदि हां, तो डेटा कैसे डाला जा सकता है " - उपयोग किए जा रहे डीबीएमएस पर निर्भर करता है। उदाहरण के लिए Postgres, Oracle, SQLite और Apache Derby deferrable constraints की अनुमति देते हैं जो इसे संभव बनाता है। अन्य DBMS के साथ आप भाग्य से बाहर हैं (लेकिन मैं अभी भी पहली बार में इस तरह की बाधा की आवश्यकता पर विवाद
करूंगा

जवाबों:


12

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

कहा जाता है कि, मेरी व्यक्तिगत प्राथमिकता निम्नलिखित सेटअप के लिए होगी:

CREATE TABLE dbo.Accounts
(
    AccountID INT NOT NULL
        CONSTRAINT PK_Accounts
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , AccountName VARCHAR(255)
);

CREATE TABLE dbo.Contacts
(
    ContactID INT NOT NULL
        CONSTRAINT PK_Contacts
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , ContactName VARCHAR(255)
);

CREATE TABLE dbo.AccountsContactsXRef
(
    AccountsContactsXRefID INT NOT NULL
        CONSTRAINT PK_AccountsContactsXRef
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , AccountID INT NOT NULL
        CONSTRAINT FK_AccountsContactsXRef_AccountID
        FOREIGN KEY REFERENCES dbo.Accounts(AccountID)
    , ContactID INT NOT NULL
        CONSTRAINT FK_AccountsContactsXRef_ContactID
        FOREIGN KEY REFERENCES dbo.Contacts(ContactID)
    , IsPrimary BIT NOT NULL 
        CONSTRAINT DF_AccountsContactsXRef
        DEFAULT ((0))
    , CONSTRAINT UQ_AccountsContactsXRef_AccountIDContactID
        UNIQUE (AccountID, ContactID)
);

CREATE UNIQUE INDEX IX_AccountsContactsXRef_Primary
ON dbo.AccountsContactsXRef(AccountID, IsPrimary)
WHERE IsPrimary = 1;

यह करने की क्षमता प्रदान करता है:

  1. स्पष्ट रूप से संपर्क और खातों के बीच संबंधों को एक क्रॉस-रेफरेंस टेबल के माध्यम से चित्रित करते हैं जिस तरह से पीटर अपने जवाब में सुझाते हैं
  2. एक ध्वनि, गैर-परिपत्र तरीके से संदर्भात्मक अखंडता बनाए रखें।
  3. सूचकांक के माध्यम से प्राथमिक संपर्कों की एक उच्च बनाए रखने योग्य सूची के लिए प्रदान करें IX_AccountsContactsXRef_Primary। इस इंडेक्स में एक फ़िल्टर होता है, इसलिए यह केवल उन प्लेटफ़ॉर्म पर काम करेगा जो उनका समर्थन करते हैं। चूंकि यह सूचकांक UNIQUEविकल्प के साथ निर्दिष्ट है , इसलिए प्रत्येक खाते के लिए केवल एक ही प्राथमिक संपर्क हो सकता है।

उदाहरण के लिए, यदि आप "प्राथमिक" स्थिति को दर्शाने वाले कॉलम के साथ सभी संपर्कों की सूची प्रदर्शित करना चाहते हैं, तो प्रत्येक खाते के लिए सूची के शीर्ष पर प्राथमिक संपर्क दिखा सकते हैं, आप कर सकते हैं:

SELECT A.AccountName
    , C.ContactName
    , XR.IsPrimary
FROM dbo.Accounts A
    INNER JOIN dbo.AccountsContactsXRef XR ON A.AccountID = XR.AccountID
    INNER JOIN dbo.Contacts C ON XR.ContactID = C.ContactID
ORDER BY A.AccountName
    , XR.IsPrimary DESC
    , C.ContactName;

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

ALTER TABLE dbo.AccountsContactsXRef
ADD IsActive BIT NOT NULL
CONSTRAINT DF_AccountsContactsXRef_IsActive
DEFAULT ((1));

CREATE INDEX IX_AccountsContactsXRef_IsActive
ON dbo.AccountsContactsXRef(IsActive)
WHERE IsActive = 1;

1
क्या आप कहेंगे कि सामान्य तौर पर, परिपत्र संदर्भों से बचा जाना चाहिए? मेरी राय है कि वे खराब नहीं हैं और प्रभावी डिजाइन को पूरा करने के लिए उनका उपयोग किया है। वे हटाते हैं कि वे इसमें और अधिक जटिल हो जाते हैं और उन्हें अन्यथा NULL-माता-पिता इकाई में NULL को अपडेट करने और अपडेट करने की आवश्यकता होती है, लेकिन मुझे लगता है कि सुविधा के लिए कम कीमत चुकानी होगी। मैं उन्हें Postgres में उपयोग करता हूं, जहां FK फ़ील्ड अशक्त है, इसलिए मैं इसके साथ एक पंक्ति बनाता हूं NULL और फिर चाइल्ड टेबल से PK के लिए FK फ़ील्ड को अपडेट करता हूं, वही फ़ंक्शन पूरा करता है जो ओपी में वर्णित है
द्विधा गतिवाला

मुझे परिपत्र संदर्भ पसंद नहीं हैं, क्योंकि वे अनावश्यक रूप से डिजाइन को जटिल करते हैं, और अधिकांश समय व्यापार बंद करने के लायक कोई महत्वपूर्ण प्रदर्शन लाभ नहीं देते हैं। मैं ओकाम के रेजर का प्रशंसक हूं, और परिणामस्वरूप दिए गए समस्या के लिए सबसे सरल समाधान की ओर हूं।
मैक्स वेरनॉन

1
मैं ऑकैम के रेजर के लिए सभी हूं, लेकिन एब्सर्ड डिजाइन ने मुझे कुछ सामान्य प्रश्नों का उल्लंघन करने में सक्षम किया है, जबकि 3 के सामान्य रूप का उल्लंघन नहीं किया गया है। मैं आपकी प्रतिक्रिया की सराहना करता हूँ
उभयचर

6

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

CREATE TABLE Account
(
    ID INT PRIMARY KEY IDENTITY,
    Name VARCHAR(50)
)

CREATE TABLE Contact
(
    ID INT PRIMARY KEY IDENTITY,
    Name VARCHAR(50),
)

CREATE TABLE AccountContact
(
    AccountID INT FOREIGN KEY REFERENCES Account(ID),
    ContactID INT FOREIGN KEY REFERENCES Contact(ID),

    primary key(AccountID,ContactID)
)

5
" डेटा डालना असंभव होगा " - नहीं, यह असंभव नहीं होगा। बस अड़चनों को अपवित्र घोषित कर दो। लेकिन मैं सहमत हूं: लगभग सभी मामलों में परिपत्र संदर्भ एक खराब डिजाइन हैं।
a_horse_with_no_name

3
@a_horse - SQL Server में एक डिफरेंशियल रेफरेंस को परिभाषित करना संभव नहीं है ... मुझे पता है कि आप Oracle में कर सकते हैं, बस विसंगति को इंगित करना चाहते थे।
मैक्स वर्नोन

2
@MaxVernon: सवाल केवल SQL सर्वर के बारे में नहीं है और केवल Oracle की तुलना में अधिक DBMS हैं जो डिफ्रैबल बाधाओं का समर्थन करते हैं - लेकिन जैसा कि मैंने कहा: मैं Pieter से सहमत हूं कि डिज़ाइन स्वयं गलत है (और उसका समाधान बहुत अधिक समझ में आता है)
a_horse_with_no_name

4
किसी भी एक उदाहरण की बारीकियों को छोड़कर, सामान्य शब्दों में पारस्परिक (यानी "परिपत्र") संदर्भात्मक अखंडता बाधाओं के बारे में कुछ भी गलत या "त्रुटिपूर्ण" नहीं है। यह प्रभाव में शामिल होने की निर्भरता का सिर्फ एक उदाहरण है। यदि आपके DBMS आपको उन्हें लागू करने की अनुमति देता है, तो निर्भरता में शामिल होना एक अच्छी बात है। यह सिर्फ SQL DBMSs में तालिकाओं के बीच जटिल निर्भरता को लागू करना बहुत आसान नहीं है।
nvogel

6
@ पीटर, 1-1 एक सम्मिलित निर्भरता का एकमात्र उदाहरण नहीं है, और यह विशेष रूप से विशेष मामला भी नहीं है। ऐसे मामले हैं जहां निर्भरता की कमी में शामिल होने से सही समझ बनती है।
nvogel

1

आप खाते के बजाय अपने बाहरी ऑब्जेक्ट को प्राथमिक संपर्क से जोड़ सकते हैं। आपका डेटा इस तरह दिखाई देगा:

CREATE TABLE Account
(
    ID INT PRIMARY KEY IDENTITY,
    Name VARCHAR(50)
)

CREATE TABLE Contact
(
    ID INT PRIMARY KEY IDENTITY,
    Name VARCHAR(50),
    AccountID INT FOREIGN KEY REFERENCES Account(ID)
)

CREATE TABLE AccountOwner (
    Other Stuff Here . . .
    PrimaryContactID INT FOREIGN KEY REFERENCES Contact(ID)
)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.