(इस विषय के बारे में एक लेख को फिर से खोजने की कोशिश करते समय मुझे यह सवाल आया था। अब जब मैंने इसे पा लिया है, तो मैं इसे यहाँ पोस्ट कर रहा हूँ अगर अन्य लोग वर्तमान में चुने गए उत्तर के वैकल्पिक विकल्प की खोज में हैं - row_number()
)
मेरे पास यही उपयोग मामला है। हमारे सास में एक विशिष्ट परियोजना में डाले गए प्रत्येक रिकॉर्ड के लिए हमें एक अद्वितीय, वृद्धि संख्या की आवश्यकता होती है जो समवर्ती INSERT
एस के चेहरे में उत्पन्न हो सकती है और आदर्श रूप से अंतरहीन है।
यह लेख एक अच्छे समाधान का वर्णन करता है , जिसे मैं यहाँ आसानी और संक्षिप्तता के लिए संक्षेप में प्रस्तुत करूँगा।
- एक अलग तालिका है जो अगले मूल्य प्रदान करने के लिए काउंटर के रूप में कार्य करती है। इसमें दो कॉलम होंगे,
document_id
और counter
। counter
हो जाएगा DEFAULT 0
वैकल्पिक रूप से, अगर आप पहले से ही एक है document
इकाई है कि समूहों सभी संस्करणों, एक counter
वहाँ जोड़ा जा सकता है।
- तालिका में एक
BEFORE INSERT
ट्रिगर जोड़ें document_versions
जो परमाणु रूप से काउंटर बढ़ाता है ( UPDATE document_revision_counters SET counter = counter + 1 WHERE document_id = ? RETURNING counter
) और फिर NEW.version
उस काउंटर मान पर सेट होता है।
वैकल्पिक रूप से, आप आवेदन परत पर ऐसा करने के लिए एक सीटीई का उपयोग करने में सक्षम हो सकते हैं (हालांकि मैं इसे प्राथमिकता के लिए ट्रिगर होना पसंद करता हूं):
WITH version AS (
UPDATE document_revision_counters
SET counter = counter + 1
WHERE document_id = 1
RETURNING counter
)
INSERT
INTO document_revisions (document_id, rev, other_data)
SELECT 1, version.counter, 'some other data'
FROM "version";
यह सिद्धांत में समान है कि आप इसे शुरू में हल करने के लिए कैसे प्रयास कर रहे थे, सिवाय इसके कि एक बयान में एक काउंटर पंक्ति को संशोधित करके यह तब तक बासी मूल्य के रीड को ब्लॉक करता INSERT
है जब तक कि यह प्रतिबद्ध नहीं है।
psql
इस कार्रवाई में इसे दिखाने से एक प्रतिलेख है :
scratch=# CREATE TABLE document_revisions (document_id integer, rev integer, other_data text, PRIMARY KEY (document_id, rev));
CREATE TABLE
scratch=# CREATE TABLE document_revision_counters (document_id integer PRIMARY KEY, counter integer DEFAULT 0);
CREATE TABLE
scratch=# WITH version AS (
INSERT INTO document_revision_counters (document_id) VALUES (2)
ON CONFLICT (document_id)
DO UPDATE SET counter = document_revision_counters.counter + 1
RETURNING counter;
)
INSERT
INTO document_revisions (document_id, rev, other_data)
SELECT 2, version.counter, 'doc 1 v1'
FROM "version";
INSERT 0 1
scratch=# WITH version AS (
INSERT INTO document_revision_counters (document_id) VALUES (2)
ON CONFLICT (document_id)
DO UPDATE SET counter = document_revision_counters.counter + 1
RETURNING counter;
)
INSERT
INTO document_revisions (document_id, rev, other_data)
SELECT 2, version.counter, 'doc 1 v2'
FROM "version";
INSERT 0 1
scratch=# WITH version AS (
INSERT INTO document_revision_counters (document_id) VALUES (2)
ON CONFLICT (document_id)
DO UPDATE SET counter = document_revision_counters.counter + 1
RETURNING counter;
)
INSERT
INTO document_revisions (document_id, rev, other_data)
SELECT 2, version.counter, 'doc 2 v1'
FROM "version";
INSERT 0 1
scratch=# SELECT * FROM document_revisions;
document_id | rev | other_data
-------------+-----+------------
2 | 1 | doc 1 v1
2 | 2 | doc 1 v2
2 | 1 | doc 2 v1
(3 rows)
जैसा कि आप देख सकते हैं, आपको सावधान रहना INSERT
होगा कि कैसे होता है, इसलिए ट्रिगर संस्करण, जो इस तरह दिखता है:
CREATE OR REPLACE FUNCTION set_doc_revision()
RETURNS TRIGGER AS $$ BEGIN
WITH version AS (
INSERT INTO document_revision_counters (document_id, counter) VALUES (NEW.document_id, 1)
ON CONFLICT (document_id)
DO UPDATE SET counter = document_revision_counters.counter + 1
RETURNING counter
)
SELECT INTO NEW.rev counter FROM version; RETURN NEW; END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER set_doc_revision BEFORE INSERT ON document_revisions
FOR EACH ROW EXECUTE PROCEDURE set_doc_revision();
यह INSERT
बहुत अधिक सीधे आगे बनाता है और डेटा की अखंडता INSERT
मनमाने स्रोतों से उत्पन्न होने के कारण अधिक मजबूत होती है:
scratch=# INSERT INTO document_revisions (document_id, other_data) VALUES (1, 'baz');
INSERT 0 1
scratch=# INSERT INTO document_revisions (document_id, other_data) VALUES (1, 'foo');
INSERT 0 1
scratch=# INSERT INTO document_revisions (document_id, other_data) VALUES (1, 'bar');
INSERT 0 1
scratch=# INSERT INTO document_revisions (document_id, other_data) VALUES (42, 'meaning of life');
INSERT 0 1
scratch=# SELECT * FROM document_revisions;
document_id | rev | other_data
-------------+-----+-----------------
1 | 1 | baz
1 | 2 | foo
1 | 3 | bar
42 | 1 | meaning of life
(4 rows)