आपको ट्रिगर या PL / pgSQL की बिल्कुल भी आवश्यकता नहीं है।
तुम भी बाधाओं की जरूरत नहीं है DEFERRABLE
।
और आपको किसी भी जानकारी को अनावश्यक रूप से संग्रहीत करने की आवश्यकता नहीं है।
users
तालिका में सक्रिय ईमेल की आईडी शामिल करें , जिसके परिणामस्वरूप पारस्परिक संदर्भ मिलते हैं। कोई सोच सकता है कि हमें DEFERRABLE
उपयोगकर्ता और उसके सक्रिय ईमेल को सम्मिलित करने के लिए चिकन-एंड-एग समस्या को हल करने के लिए एक बाधा की आवश्यकता है , लेकिन डेटा-संशोधित सीटीई का उपयोग करके हमें इसकी आवश्यकता भी नहीं है।
यह हर समय उपयोगकर्ता के प्रति एक सक्रिय ईमेल को लागू करता है :
CREATE TABLE users (
user_id serial PRIMARY KEY
, username text NOT NULL
, email_id int NOT NULL -- FK to active email, constraint added below
);
CREATE TABLE email (
email_id serial PRIMARY KEY
, user_id int NOT NULL REFERENCES users ON DELETE CASCADE ON UPDATE CASCADE
, email text NOT NULL
, CONSTRAINT email_fk_uni UNIQUE(user_id, email_id) -- for FK constraint below
);
ALTER TABLE users ADD CONSTRAINT active_email_fkey
FOREIGN KEY (user_id, email_id) REFERENCES email(user_id, email_id);
इसे "सबसे अधिक सक्रिय ईमेल पर" बनाने के लिए NOT NULL
बाधा को दूर users.email_id
करें। (आप अभी भी प्रति उपयोगकर्ता कई ईमेल संग्रहीत कर सकते हैं, लेकिन उनमें से कोई भी "सक्रिय" नहीं है।)
आप अधिक लेवे की अनुमति दे सकते हैं active_email_fkey
DEFERRABLE
(एक ही लेनदेन के अलग-अलग कमांड में उपयोगकर्ता और ईमेल डालें ), लेकिन यह आवश्यक नहीं है ।
इंडेक्स कवरेज को ऑप्टिमाइज़ करने के लिए मैंने user_id
पहले UNIQUE
बाधा डाली email_fk_uni
। विवरण:
वैकल्पिक दृश्य:
CREATE VIEW user_with_active_email AS
SELECT * FROM users JOIN email USING (user_id, email_id);
यहां बताया गया है कि आप नए उपयोगकर्ताओं को एक सक्रिय ईमेल के साथ कैसे डालें (आवश्यकतानुसार):
WITH new_data(username, email) AS (
VALUES
('usr1', 'abc@d.com') -- new users with *1* active email
, ('usr2', 'def3@d.com')
, ('usr3', 'ghi1@d.com')
)
, u AS (
INSERT INTO users(username, email_id)
SELECT n.username, nextval('email_email_id_seq'::regclass)
FROM new_data n
RETURNING *
)
INSERT INTO email(email_id, user_id, email)
SELECT u.email_id, u.user_id, n.email
FROM u
JOIN new_data n USING (username);
विशिष्ट कठिनाई यह है कि हमारे पास शुरू करने के लिए न तो है user_id
और न ही email_id
है। दोनों संबंधित से प्रदान किए गए सीरियल नंबर हैं SEQUENCE
। यह एक एकल RETURNING
खंड (एक और चिकन और अंडे की समस्या) के साथ हल नहीं किया जा सकता है । समाधान है nextval()
के रूप में नीचे लिंक किए गए जवाब में विस्तार से समझाया ।
यदि आप उस कॉलम के लिए संलग्न अनुक्रम का नाम नहीं जानते हैं जिसे आप प्रतिस्थापित कर सकते हैं:serial
email.email_id
nextval('email_email_id_seq'::regclass)
साथ में
nextval(pg_get_serial_sequence('email', 'email_id'))
यहां बताया गया है कि आप एक नया "सक्रिय" ईमेल कैसे जोड़ते हैं:
WITH e AS (
INSERT INTO email (user_id, email)
VALUES (3, 'new_active@d.com')
RETURNING *
)
UPDATE users u
SET email_id = e.email_id
FROM e
WHERE u.user_id = e.user_id;
एसक्यूएल फिडल।
यदि आप सर्वर-साइड फ़ंक्शंस में SQL कमांड को इनकैप्सुलेट कर सकते हैं, तो कुछ साधारण दिमाग वाले ORM इससे निपटने के लिए पर्याप्त स्मार्ट नहीं हैं।
बारीकी से संबंधित, पर्याप्त विवरण के साथ:
यह भी संबंधित:
DEFERRABLE
बाधाओं के बारे में :
के बारे में nextval()
और pg_get_serial_sequence()
: