PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

PostgreSQL में क्रॉस टेबल की कमी

स्पष्टीकरण

इस आवश्यकता . का सूत्रीकरण व्याख्या के लिए जगह छोड़ता है:
जहां UserRole.role_name एक कर्मचारी भूमिका नाम शामिल है।

मेरी व्याख्या:
UserRole में एक प्रविष्टि के साथ जिसमें role_name = 'employee' . है .

आपका नामकरण परंपरा <स्ट्राइक>है समस्याग्रस्त था (अब अपडेट किया गया)। User मानक SQL और Postgres में एक आरक्षित शब्द है। यह पहचानकर्ता के रूप में अवैध है जब तक कि डबल-उद्धृत न हो - जो कि गलत होगा। उपयोगकर्ता कानूनी नाम ताकि आपको दोहरा-उद्धरण न करना पड़े।

मैं अपने कार्यान्वयन में परेशानी मुक्त पहचानकर्ताओं का उपयोग कर रहा हूं।

समस्या

FOREIGN KEY और CHECK संबंधपरक अखंडता को लागू करने के लिए बाधा सिद्ध, वायुरोधी उपकरण हैं। ट्रिगर शक्तिशाली, उपयोगी और बहुमुखी विशेषताएं हैं लेकिन अधिक परिष्कृत, कम सख्त और डिज़ाइन त्रुटियों और कोने के मामलों के लिए अधिक जगह के साथ हैं।

आपका मामला कठिन है क्योंकि एक FK बाधा पहली बार में असंभव लगती है:इसके लिए एक PRIMARY KEY की आवश्यकता होती है या UNIQUE संदर्भ के लिए बाधा - न तो NULL मानों की अनुमति देता है। कोई आंशिक एफके बाधाएं नहीं हैं, सख्त संदर्भात्मक अखंडता से केवल बचने के लिए संदर्भ में NULL मान हैं डिफ़ॉल्ट MATCH SIMPLE . के कारण कॉलम एफके बाधाओं का व्यवहार। प्रति दस्तावेज़:

<ब्लॉकक्वॉट>

MATCH SIMPLE किसी भी विदेशी कुंजी कॉलम को शून्य होने देता है; यदि उनमें से कोई भी शून्य है, तो संदर्भित तालिका में पंक्ति का मिलान होना आवश्यक नहीं है।

अधिक के साथ dba.SE पर संबंधित उत्तर:

  • दो-स्तंभ विदेशी कुंजी बाधा केवल तभी जब तीसरा स्तंभ पूर्ण नहीं हो

वर्कअराउंड एक बूलियन ध्वज पेश करना है is_employee दोनों पक्षों के कर्मचारियों को चिह्नित करने के लिए, परिभाषित NOT NULL users . में , लेकिन होने की अनुमति है NULL user_role . में :

समाधान

यह आपकी आवश्यकताओं को लागू करता है बिल्कुल , शोर और ओवरहेड को न्यूनतम रखते हुए:

CREATE TABLE users (
   users_id    serial PRIMARY KEY
 , employee_nr int
 , is_employee bool NOT NULL DEFAULT false
 , CONSTRAINT role_employee CHECK (employee_nr IS NOT NULL = is_employee)  
 , UNIQUE (is_employee, users_id)  -- required for FK (otherwise redundant)
);

CREATE TABLE user_role (
   user_role_id serial PRIMARY KEY
 , users_id     int NOT NULL REFERENCES users
 , role_name    text NOT NULL
 , is_employee  bool CHECK(is_employee)
 , CONSTRAINT role_employee
   CHECK (role_name <> 'employee' OR is_employee IS TRUE)
 , CONSTRAINT role_employee_requires_employee_nr_fk
   FOREIGN KEY (is_employee, users_id) REFERENCES users(is_employee, users_id)
);

बस इतना ही।

ये ट्रिगर वैकल्पिक हैं लेकिन जोड़े गए टैग सेट करने की सुविधा के लिए अनुशंसित हैं is_employee स्वचालित रूप से और आपको कुछ भी करने की आवश्यकता नहीं है अतिरिक्त:

-- users
CREATE OR REPLACE FUNCTION trg_users_insup_bef()
  RETURNS trigger AS
$func$
BEGIN
   NEW.is_employee = (NEW.employee_nr IS NOT NULL);
   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER insup_bef
BEFORE INSERT OR UPDATE OF employee_nr ON users
FOR EACH ROW
EXECUTE PROCEDURE trg_users_insup_bef();

-- user_role
CREATE OR REPLACE FUNCTION trg_user_role_insup_bef()
  RETURNS trigger AS
$func$
BEGIN
   NEW.is_employee = true;
   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER insup_bef
BEFORE INSERT OR UPDATE OF role_name ON user_role
FOR EACH ROW
WHEN (NEW.role_name = 'employee')
EXECUTE PROCEDURE trg_user_role_insup_bef();

फिर से, कोई बकवास नहीं, अनुकूलित और केवल जरूरत पड़ने पर ही कॉल किया जाता है।

एसक्यूएल फिडल पोस्टग्रेज 9.3 के लिए डेमो। Postgres 9.1+ के साथ काम करना चाहिए।

प्रमुख बिंदु

  • अब, अगर हम user_role.role_name = 'employee' सेट करना चाहते हैं , तो एक मिलान user.employee_nr . होना चाहिए पहले।

  • आप अब भी एक employee_nr जोड़ सकते हैं करने के लिए किसी उपयोगकर्ता, और आप (तब) अभी भी किसी भी user_role . को टैग कर सकते हैं is_employee . के साथ , वास्तविक role_name . की परवाह किए बिना . यदि आपको आवश्यकता हो तो इसे अस्वीकार करना आसान है, लेकिन यह कार्यान्वयन आवश्यकता से अधिक प्रतिबंध नहीं लगाता है।

  • users.is_employee केवल true हो सकता है या false और एक employee_nr . के अस्तित्व को प्रतिबिंबित करने के लिए मजबूर किया जाता है CHECK . द्वारा बाधा ट्रिगर कॉलम को स्वचालित रूप से सिंक में रखता है। आप false की अनुमति दे सकते हैं इसके अलावा अन्य उद्देश्यों के लिए डिज़ाइन में केवल मामूली अपडेट के साथ।

  • user_role.is_employee . के लिए नियम थोड़े अलग हैं:यह सच होना चाहिए अगर role_name = 'employee' . एक CHECK द्वारा लागू किया गया बाधा और फिर से ट्रिगर द्वारा स्वचालित रूप से सेट करें। लेकिन इसे role_name बदलने की अनुमति है किसी और चीज़ के लिए और अभी भी is_employee keep रखें . employee_nr वाले उपयोगकर्ता को किसी ने नहीं कहा क्या आवश्यक है user_role . में एक अनुरूप प्रविष्टि प्राप्त करने के लिए , बस दूसरी तरफ! फिर से, यदि आवश्यक हो तो अतिरिक्त रूप से लागू करना आसान है।

  • यदि अन्य ट्रिगर हैं जो हस्तक्षेप कर सकते हैं, तो इस पर विचार करें:
    PostgreSQL 9.2.1 में लूपिंग ट्रिगर कॉल से कैसे बचें
    लेकिन हमें चिंता करने की ज़रूरत नहीं है कि नियमों का उल्लंघन हो सकता है क्योंकि उपरोक्त ट्रिगर केवल सुविधा के लिए हैं। प्रति नियम CHECK . के साथ लागू होते हैं और FK बाधाएं, जो बिना किसी अपवाद के अनुमति देती हैं।

  • इसके अलावा:मैंने कॉलम is_employee . रखा है सबसे पहले बाधा में UNIQUE (is_employee, users_id) किसी कारण से . users_id पहले से ही PK में शामिल है, इसलिए यह यहां दूसरा स्थान ले सकता है:
    DB सहयोगी निकाय और अनुक्रमण



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. postgresql - तालिका में प्रत्येक कॉलम की गणना (कोई शून्य मान नहीं)

  2. रेल 4 session.id कभी-कभी शून्य

  3. पोस्टग्रेएसक्यूएल में बच गए यूनिकोड चरित्र को वास्तविक चरित्र में कनवर्ट करें

  4. पोस्टग्रेज इंस्टालेशन डेटाबेस क्लस्टर इनिशियलाइज़ेशन विफल (Postgresql संस्करण 9.4.4)

  5. स्कीमा पर उपयोग अनुदान वास्तव में क्या करता है?