मैं अंतिम सम्मिलित आईडी प्राप्त करने के लिए PostgreSQL में वक्र () का उपयोग कैसे करूं?


64

मेरे पास एक टेबल है:

CREATE TABLE names (id serial, name varchar(20))

मैं उस तालिका से "अंतिम सम्मिलित आईडी" चाहता हूं, बिना RETURNING idप्रविष्टि का उपयोग किए । एक समारोह लगता है CURRVAL(), लेकिन मुझे समझ नहीं आता कि इसका उपयोग कैसे किया जाए।

मैंने कोशिश की है:

SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)

लेकिन उनमें से कोई भी काम नहीं करता है। मैं currval()अंतिम सम्मिलित आईडी प्राप्त करने के लिए कैसे उपयोग कर सकता हूं ?


2
इस समस्या / समाधान के पाठकों को इस बात की जानकारी होनी चाहिए कि आम तौर पर वक्रता () का उपयोग हतोत्साहित किया जाता है क्योंकि रिटर्न्सिंग क्लॉज अतिरिक्त क्वेरी के ओवरहेड के बिना पहचानकर्ता प्रदान करता है, और WRIT VALUE (जो वक्रता में वापसी करेगा) की संभावना के बिना कुछ उपयोग के मामले।)
chander

1
@ चंद्र: क्या आपके पास उस दावे का कोई संदर्भ है? का उपयोग currval() निश्चित रूप से हतोत्साहित नहीं है।
a_horse_with_no_name

शायद यह राय का विषय है कि क्या करवाचौथ का उपयोग हतोत्साहित किया जाता है, लेकिन कुछ मामलों में उपयोगकर्ताओं को इस बात की जानकारी होनी चाहिए कि यह एक ऐसा मूल्य प्रदान कर सकता है, जिसकी आपको उम्मीद नहीं है (इस प्रकार जहाँ बेहतर समर्थन किया गया है, उसी तरह बेहतर बनाते हुए।) ऐसी तालिका A है जो अनुक्रम a_seq का उपयोग करती है, और तालिका B जो PK स्तंभ के लिए a_seq (कॉलिंग नेवल (a_seq ') का उपयोग करती है।) मान लीजिए कि आपके पास भी एक ट्रिगर (a_trg) है जो तालिका B पर INSERT से तालिका A में सम्मिलित करता है। उस स्थिति में वक्र () फ़ंक्शन (तालिका A पर सम्मिलित होने के बाद) तालिका B पर सम्मिलित करने के लिए उत्पन्न संख्या वापस
लौटाएगी

जवाबों:


51

यदि आप एक स्तंभ बनाते हैं तो serialPostgreSQL स्वचालित रूप से उसके लिए एक अनुक्रम बनाता है।

अनुक्रम का नाम स्वचालित है और हमेशा tablename_columnname_seq है, आपके मामले में अनुक्रम नाम होंगे names_id_seq

तालिका में सम्मिलित करने के बाद, आप currval()उस अनुक्रम नाम से कॉल कर सकते हैं :

postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
CREATE TABLE
postgres=> insert into names (name) values ('Arthur Dent');
INSERT 0 1
postgres=> select currval('names_id_seq');
 currval
---------
       1
(1 row)
postgres=>

अनुक्रम नाम को हार्डकोड करने के बजाय, आप pg_get_serial_sequence()इसके बजाय उपयोग कर सकते हैं :

select currval(pg_get_serial_sequence('names', 'id'));

इस तरह आपको नामकरण की रणनीति पर भरोसा करने की आवश्यकता नहीं है जो पोस्टग्रैज का उपयोग करता है।

या यदि आप अनुक्रम नाम का उपयोग नहीं करना चाहते हैं, तो उपयोग करें lastval()


मुझे लगता है कि currval()बहु-उपयोगकर्ता सेटअप में उपयोग करना अच्छा नहीं है । जैसे एक वेबसर्वर पर।
जोनास

9
नहीं, आप गलत हैं। currval()आपके वर्तमान कनेक्शन के लिए "स्थानीय" है। इसलिए बहु-उपयोगकर्ता वातावरण में इसका उपयोग करने में कोई समस्या नहीं है। यह एक अनुक्रम का संपूर्ण उद्देश्य है।
a_horse_with_no_name

1
यह (काफी दुर्लभ) मामले में टूट सकता है जिसमें आपका इंसर्ट एक ही टेबल में अधिक आवेषण चलाता है, नहीं?
लियोनबॉय

1
@a_horse_with_no_name: मैं सोच रहा था कि कई आवेषण पर नहीं (यह आसान है स्पॉट) लेकिन मेज पर परिभाषित (शायद अज्ञात) ट्रिगर पर। उदाहरण के लिए इसे ऊपर देखें: gist.github.com/anonymous/9784814
leonbloy

1
यह हमेशा तालिका और स्तंभ नाम नहीं है। यदि उस नाम के साथ पहले से ही कोई अनुक्रम है तो वह अंत में किसी संख्या को समाप्‍त या बढ़ाकर एक नया अनुक्रम उत्पन्न करेगा, और यदि यह सीमा से अधिक है (जो कि 62 वर्ण प्रतीत होता है) नाम को छोटा करना पड़ सकता है।
फिलिब्स जूल

47

यह सीधे स्टैक ओवरफ्लो से है

जैसा कि @a_horse_with_no_name और @ जेक डगलस द्वारा बताया गया था, करावल चालू सत्र के साथ ही काम करता है। इसलिए यदि आप इस तथ्य से ठीक हैं कि परिणाम किसी अन्य सत्र के अनअमेज्ड लेन-देन से प्रभावित हो सकता है, और आप अभी भी कुछ चाहते हैं जो सत्रों में काम करेगा, तो आप इसका उपयोग कर सकते हैं:

SELECT last_value FROM your_sequence_name;

अधिक जानकारी के लिए एसओ के लिंक का उपयोग करें।

हालांकि, डाकघरों के दस्तावेज से यह स्पष्ट रूप से कहा गया है कि

यदि अगले सत्र को वर्तमान सत्र में नहीं बुलाया गया है, तो यह अंतिम रूप से कॉल करने के लिए एक त्रुटि है।

इसलिए मुझे लगता है कि सत्रों के अनुक्रम के लिए कर्वल या last_value का ठीक से उपयोग करने के लिए आप सख्ती से बोल रहे हैं, आपको ऐसा कुछ करने की आवश्यकता होगी?

SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);

यह मानते हुए कि वर्तमान सत्र में आपके पास धारावाहिक क्षेत्र का उपयोग करने का कोई अन्य तरीका नहीं होगा।


3
मैं ऐसी स्थिति के बारे में नहीं सोच सकता जब यह उपयोगी होगा।
ypercube y

मैं बस सोच रहा था कि क्या यह वक्रता प्राप्त करने का एक तरीका है, यदि अगले सत्र को वर्तमान सत्र में नहीं बुलाया गया है। कोई सुझाव तो?
14

मुझे यह तब करना पड़ा जब मैं हार्ड-कोडिंग उत्पन्न कुंजी के लिए प्राथमिक कुंजी कोडिंग डेटा था जहां मैं पीके मूल्यों को चाहता था जो सामान्य रूप से ग्राहक परीक्षण को आसान बनाने के लिए समय से पहले निर्धारित किया जाना था। आवेषण का समर्थन करने के लिए जब आप उस कॉलम पर करते हैं जो सामान्य रूप से nextval()आपके द्वारा डिफ़ॉल्ट मान से शासित होता है, तो हार्डकोड आईडी के साथ आपके द्वारा डाले गए स्थिरता रिकॉर्ड की संख्या से मिलान करने के लिए मैन्युअल रूप से अनुक्रम सेट करना होगा। इसके अलावा, वक्र () / अंतिम () पूर्व अगले उपलब्ध नहीं होने की समस्या के समाधान का तरीका सिर्फ SELECTसीधे अनुक्रम पर है।
पीटर एम। इलियास

@ ypercube y इसके विपरीत, मैं "सही" उत्तर का उपयोग करने के लिए कोई अच्छा कारण नहीं सोच सकता जो चुना गया था। इस उत्तर को तालिका में रिकॉर्ड सम्मिलित करने की आवश्यकता नहीं है। यह प्रश्न का उत्तर देता है। फिर से, मैं बिना चुने हुए इस उत्तर का उपयोग करने का कोई अच्छा कारण नहीं सोच सकता।
हेनले चिउ

1
इस उत्तर में तालिका को संशोधित करना शामिल नहीं है। जाँच एक करता है। आदर्श रूप से, आप बस अंतिम आईडी जानना चाहते हैं, जिसमें कोई बदलाव नहीं किया गया है। यदि यह उत्पादन डीबी है तो क्या होगा? आप संभव टक्करों के बिना एक यादृच्छिक पंक्ति नहीं डाल सकते। इस प्रकार यह उत्तर सुरक्षित होने के साथ-साथ सही भी है।
हेनले चिउ

14

आपको इस सत्र में इस क्रम के लिए पहले कॉल nextvalकरना होगाcurrval :

create sequence serial;
select nextval('serial');
 nextval
---------
       1
(1 row)

select currval('serial');
 currval
---------
       1
(1 row)

इसलिए आप अनुक्रम से 'अंतिम सम्मिलित आईडी' तब तक नहीं खोज सकते जब तक कि insertएक ही सत्र में नहीं किया जाता है (लेन-देन वापस हो सकता है लेकिन अनुक्रम लागू नहीं होगा)

जैसा कि a_horse के उत्तर में बताया गया है, create tableस्तंभ का प्रकार serialस्वचालित रूप से एक अनुक्रम बनाएगा और स्तंभ के लिए डिफ़ॉल्ट मान उत्पन्न करने के लिए इसका उपयोग करेगा, इसलिए insertसामान्य रूप से अनुमानित रूप से उपयोग किया जाता nextvalहै:

create table my_table(id serial);
NOTICE:  CREATE TABLE will create implicit sequence "my_table_id_seq" for 
         serial column "my_table.id"

\d my_table
                          Table "stack.my_table"
 Column |  Type   |                       Modifiers
--------+---------+-------------------------------------------------------
 id     | integer | not null default nextval('my_table_id_seq'::regclass)

insert into my_table default values;
select currval('my_table_id_seq');
 currval
---------
       1
(1 row)

3

तो इन विभिन्न तरीकों के साथ कुछ मुद्दे हैं:

कर्रवल को केवल वर्तमान सत्र में उत्पन्न अंतिम मान प्राप्त होता है - जो महान है यदि आपके पास कुछ और नहीं है मान उत्पन्न करना, लेकिन उन मामलों में जहां आप ट्रिगर को कॉल कर सकते हैं और / या वर्तमान लेनदेन में एक से अधिक बार अनुक्रम उन्नत है। सही मान वापस नहीं जा रहा है। यह 99% लोगों के लिए कोई समस्या नहीं है - लेकिन यह कुछ ऐसा है जिसे किसी को ध्यान में रखना चाहिए।

एक सम्मिलित ऑपरेशन के बाद निर्दिष्ट किए गए विशिष्ट पहचानकर्ता को प्राप्त करने का सबसे अच्छा तरीका RETURNING खंड है। नीचे दिया गया उदाहरण मानता है कि अनुक्रम से बंधा स्तंभ "आईडी" कहलाता है:

insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;

ध्यान दें कि पुनरावृत्ति खंड की उपयोगिता केवल अनुक्रम प्राप्त करने से आगे जाती है, क्योंकि यह भी होगा:

  • "फ़ाइनल इंसर्ट" के लिए उपयोग किए जाने वाले रिटर्न मान (उदाहरण के लिए, BEFORE ट्रिगर द्वारा डाले जा रहे डेटा में परिवर्तन हो सकता है।)
  • हटाए जा रहे मान लौटाएं:

    तालिका से हटाएं जहां आईडी> 100 रिटर्निंग *

  • किसी अद्यतन के बाद संशोधित पंक्तियाँ लौटाएँ:

    अद्यतन तालिका A सेट X = 'y' जहाँ blah = 'blch' लौट रहा है *

  • अपडेट के लिए डिलीट के परिणाम का उपयोग करें:

    A के साथ (डिलीट * ए से टेबल ए के रूप में रिटर्निंग आईडी) अपडेट बी सेट हटा दिया गया है = सच जहां आईडी (ए से चयन आईडी);


बेशक, ओपी ने स्पष्ट रूप से कहा कि वे एक RETURNINGखंड का उपयोग नहीं करना चाहते हैं - लेकिन, दूसरों के लिए इसे स्पष्ट करने के लाभों का उपयोग करने में कुछ भी गलत नहीं है।
RDFozz

मैं वास्तव में विभिन्न अन्य तरीकों के नुकसान को इंगित करने की कोशिश कर रहा था (जब तक कि कोई सावधान नहीं था, यह अपेक्षित मूल्य के अलावा एक मूल्य वापस कर सकता है) - और सबसे अच्छा अभ्यास स्पष्ट करें।
chander

1

मुझे SQLALchemy का उपयोग करने के बावजूद क्वेरी को निष्पादित करना पड़ा क्योंकि मैं वक्र का उपयोग करने में सफल नहीं था।

nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1

यह एक पायथन फ्लास्क + पोस्टग्रैस्कल प्रोजेक्ट था।


1

यदि आप कॉल किए बिना अनुक्रमों का मूल्य प्राप्त करना चाहते हैं nextval(), और अनुक्रम को संशोधित किए बिना, मैंने इसे संभालने के लिए एक PL / pgSQL फ़ंक्शन को एक साथ फेंक दिया: सभी डेटाबेस अनुक्रमों का मान ढूंढें


1

आपको GRANTइस तरह स्कीमा पर उपयोग करने की आवश्यकता है :

GRANT USAGE ON SCHEMA schema_name to user;

तथा

GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;

1
Dba.se में आपका स्वागत है! अपनी पहली पोस्ट पर चीयर्स! ऐसा नहीं लगता है कि मूल पोस्ट विशेष रूप से अनुमतियों के बारे में है। शायद currval()इस थ्रेड को थोड़ा और अधिक प्रासंगिक बनाने के लिए फ़ंक्शन को कॉल करते समय अनुमतियों की विफलताओं के आसपास कुछ बारीकियों को शामिल करने के लिए अपने उत्तर का विस्तार करने पर विचार करें ?
पीटर वांडिवियर

0

PostgreSQL 11.2 में आप अनुक्रम को एक तालिका की तरह मान सकते हैं:

उदाहरण के लिए यदि आपके पास एक अनुक्रम है: 'name_id_seq'

select * from names_id_seq;
 last_value | log_cnt | is_called
------------+---------+-----------
          4 |      32 | t
(1 row)

इससे आपको अंतिम सम्मिलित आईडी (इस मामले में 4) मिलनी चाहिए, जिसका अर्थ है कि वर्तमान मूल्य (या आईडी के लिए उपयोग किया जाने वाला मूल्य) 5 होना चाहिए।


-2

PostgreSQL के विभिन्न संस्करणों में वर्तमान या अगली अनुक्रम आईडी प्राप्त करने के लिए अलग-अलग कार्य हो सकते हैं।

सबसे पहले, आपको अपने Postgres के संस्करण को जानना होगा। चुनिंदा संस्करण () का उपयोग करना; संस्करण प्राप्त करने के लिए।

PostgreSQL 8.2.15 में, आपको वर्तमान अनुक्रम आईडी का उपयोग करके मिलता है select last_value from schemaName.sequence_name

यदि उपरोक्त कथन काम नहीं करता है, तो आप उपयोग कर सकते हैं select currval('schemaName.sequence_name');


2
अलग-अलग संस्करणों के लिए कोई प्रमाण इसे अलग तरीके से कर रहा है?
dezso
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.