अंतिम सम्मिलित ID के लिए PostgreSQL फ़ंक्शन


321

PostgreSQL में, मुझे अंतिम आईडी तालिका में सम्मिलित कैसे करनी है?

MS SQL में SCOPE_IDENTITY () है।

कृपया मुझे ऐसा कुछ उपयोग करने की सलाह न दें:

select max(id) from table

आप अधिकतम फ़ंक्शन से नफरत क्यों करते हैं? मुझे लगता है कि यह बहुत सरल है। क्या सुरक्षा जैसी कोई समस्या है?
jeongmin.cha

9
@ jeongmin.cha समस्या है अगर बीच में अन्य ऑपरेशन हैं, और अधिक सम्मिलन (समवर्ती संचालन), मतलब अधिकतम आईडी बदल गया है, जब तक और जब तक आप स्पष्ट रूप से ताला नहीं लेते हैं और इसे जारी नहीं करते हैं
रोहनगरवाल

यदि इच्छित उपयोग का मामला अंतिम सम्मिलित आईडी का उपयोग उसके बाद के सम्मिलित मूल्य के हिस्से के रूप में करना है, तो यह प्रश्न देखें ।
फ्लक्स

जवाबों:


606

(( tl;drगोटो ऑप्शन 3: INSERT with RETURNING)

याद PostgreSQL में तालिकाओं के लिए कोई "आईडी" अवधारणा है कि वहाँ, बस दृश्यों (जो आमतौर पर लेकिन नहीं कर रहे हैं जरूरी साथ, किराए की प्राथमिक कुंजी के लिए डिफ़ॉल्ट मान के रूप में इस्तेमाल बम छद्म प्रकार)।

यदि आप एक नई सम्मिलित पंक्ति की आईडी प्राप्त करने में रुचि रखते हैं, तो कई तरीके हैं:


विकल्प 1: CURRVAL(<sequence name>);

उदाहरण के लिए:

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval('persons_id_seq');

अनुक्रम का नाम ज्ञात होना चाहिए, यह वास्तव में मनमाना है; इस उदाहरण में हम मानते हैं कि तालिका personsमें छद्म प्रकार idके साथ एक स्तंभ बनाया गया है SERIAL। इस पर भरोसा करने और अधिक स्वच्छ महसूस करने के लिए, आप इसके बजाय उपयोग कर सकते हैं pg_get_serial_sequence:

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval(pg_get_serial_sequence('persons','id'));

कैविएट: currval()एक ही सत्र मेंINSERT (जो निष्पादित किया गया है nextval()) के बाद ही काम करता है ।


विकल्प 2: LASTVAL();

यह पिछले की तरह ही है, केवल आपको अनुक्रम नाम निर्दिष्ट करने की आवश्यकता नहीं है: यह सबसे हाल ही में संशोधित अनुक्रम (हमेशा आपके सत्र के अंदर, ऊपर के रूप में समान चेतावनी) के लिए दिखता है।


दोनों CURRVALऔर LASTVALपूरी तरह से सुरक्षित हैं। पीजी में अनुक्रम के व्यवहार को डिज़ाइन किया गया है ताकि विभिन्न सत्रों में हस्तक्षेप न हो, इसलिए दौड़ की स्थिति का कोई जोखिम नहीं है (यदि कोई अन्य सत्र मेरे INSERT और मेरे चयन के बीच एक और पंक्ति सम्मिलित करता है, तो मुझे अभी भी अपना सही मूल्य मिलता है)।

हालांकि उनके पास एक सूक्ष्म संभावित समस्या है। यदि डेटाबेस में कुछ TRIGGER (या RULE) हैं, जो personsतालिका में सम्मिलित करने पर , अन्य तालिकाओं में कुछ अतिरिक्त सम्मिलन करता है ... तो LASTVALशायद हमें गलत मान देगा। समस्या तब भी हो सकती है CURRVAL, यदि अतिरिक्त प्रविष्टि एक ही personsतालिका में की जाती है (यह बहुत कम सामान्य है, लेकिन जोखिम अभी भी मौजूद है)।


विकल्प 3: के INSERTसाथRETURNING

INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;

यह आईडी प्राप्त करने का सबसे साफ, कुशल और सुरक्षित तरीका है। इसमें पहले के कोई भी जोखिम नहीं हैं।

कमियां? लगभग कोई नहीं: आपको अपने INSERT स्टेटमेंट को कॉल करने के तरीके को संशोधित करने की आवश्यकता हो सकती है (सबसे खराब स्थिति में, शायद आपकी API या DB परत किसी INSERT से कोई मान वापस करने की उम्मीद नहीं करती है); यह मानक SQL नहीं है (जो परवाह करता है); यह Postgresql 8.2 (Dec 2006 ...) के बाद से उपलब्ध है


निष्कर्ष: यदि आप कर सकते हैं, तो विकल्प 3 पर जाएं। कहीं और, 1 को प्राथमिकता दें।

नोट: यदि आप विश्व स्तर पर अंतिम सम्मिलित आईडी प्राप्त करने का इरादा नहीं रखते हैं (तो जरूरी नहीं कि आपके सत्र से) ये सभी विधियां बेकार हैं । इसके लिए, आपको SELECT max(id) FROM table(निश्चित रूप से, यह अन्य लेनदेन से अप्रयुक्त आवेषण नहीं पढ़ा जाएगा) का सहारा लेना चाहिए ।

इसके विपरीत, आपको ऊपर दिए गए 3 विकल्पों में से एक के बजाय कभी भी उपयोग नहीं करना चाहिए SELECT max(id) FROM table, अपने INSERTस्टेटमेंट द्वारा सिर्फ आईडी जनरेट करने के लिए , क्योंकि (प्रदर्शन के अलावा) यह समवर्ती सुरक्षित नहीं है: आपके INSERTऔर आपके SELECTदूसरे सत्र के बीच एक और रिकॉर्ड सम्मिलित हो सकता है।


25
LASTVAL () बहुत बुरी हो सकती है, यदि आप किसी ट्रिगर / नियम को दूसरी तालिका में खुद पर पंक्तियाँ डालते हैं।
कोउर सपारेव

3
SELECT max(id)दुर्भाग्य से आप जैसे ही पंक्तियों को हटाना शुरू करते हैं, वैसे ही काम नहीं करते हैं।
साइमन ए। युगस्टर

2
@leonbloy जब तक मैं कुछ याद नहीं करता, अगर आपके पास आईडी के साथ पंक्तियाँ हैं 1,2,3,4,5और पंक्तियों को हटा दें 4 और 5, अंतिम सम्मिलित आईडी अभी भी 5 है, लेकिन max()रिटर्न 3.
साइमन ए। यूगस्टर

9
किसी RETURNING id;अन्य तालिका में इसे सम्मिलित करने के लिए उपयोग करने का एक नमूना स्वागत योग्य होगा!
ओलिवियर पोंस

8
मैं कमांड लाइन टूल RETURNING idको खिलाए गए एसक्यूएल स्क्रिप्ट के भीतर कैसे उपयोग कर सकता हूं psql?
amoe

82

INSERT स्टेटमेंट के रीटर्निंग क्लॉज को देखें । असल में, INSERT एक क्वेरी के रूप में दोगुना हो जाता है और आपको वह मान वापस देता है जो डाला गया था।


4
संस्करण 8.2 के रूप में काम करता है और सबसे अच्छा और सबसे तेज़ समाधान है।
फ्रैंक हाइकेन्स

9
शायद कहा कि आईडी का उपयोग करने का एक त्वरित विवरण आईडी लौटाया?
एंड्रयू

@ और मुझे यकीन नहीं है कि मैं सवाल समझ गया हूँ। क्या आप नहीं जानते कि क्वेरी से परिणाम कैसे प्राप्त करें? यह भाषा / पुस्तकालय पर निर्भर है और चाहे आप एक का चयन कर रहे हैं या एक वापसी डालने की परवाह किए बिना काम करना चाहिए। केवल दूसरी व्याख्या जो मैं कर सकता हूं, वह यह है कि आपने कॉल से आईडी को सफलतापूर्वक पुनर्प्राप्त कर लिया है और यह नहीं जानते कि यह किस लिए है ... किस मामले में, आप इसे पुनर्प्राप्त क्यों कर रहे थे?
क्वाटफोर्ड २०'१६

8
@ और, यदि आप psql कमांड लाइन से इसे चलाते हैं : insert into names (firstname, lastname) values ('john', 'smith') returning id;तो यह बस आईडी को आउटपुट करता है जैसे कि आप select id from names where id=$lastidसीधे भागते हैं। यदि आप रिटर्न को एए वेरिएबल में सेव करना चाहते हैं , तो insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;यदि किसी स्टेटमेंट में रिटर्निंग स्टेटमेंट अंतिम स्टेटमेंट है , तो आईडी returning'एड होने के नाते फंक्शन द्वारा लौटा दिया जाता है।
अलेक्जेंडर बर्ड

32

आप निम्नलिखित की तरह, INSERT स्टेटमेंट में रिटर्निंग क्लॉज का उपयोग कर सकते हैं

wgzhao=# create table foo(id int,name text);
CREATE TABLE
wgzhao=# insert into foo values(1,'wgzhao') returning id;
 id 
----
  1
(1 row)

INSERT 0 1
wgzhao=# insert into foo values(3,'wgzhao') returning id;
 id 
----
  3
(1 row)

INSERT 0 1

wgzhao=# create table bar(id serial,name text);
CREATE TABLE
wgzhao=# insert into bar(name) values('wgzhao') returning id;
 id 
----
  1
(1 row)

INSERT 0 1
wgzhao=# insert into bar(name) values('wgzhao') returning id;
 id 
----
  2
(1 row)

INSERT 0 

28

लियोनब्लो का जवाब काफी पूर्ण है। मैं केवल उस विशेष मामले को जोड़ूंगा जिसमें किसी को PL / pgSQL फ़ंक्शन के भीतर अंतिम सम्मिलित मान प्राप्त करने की आवश्यकता होती है जहां विकल्प 3 बिल्कुल फिट नहीं होते हैं।

उदाहरण के लिए, यदि हमारे पास निम्न तालिकाएँ हैं:

CREATE TABLE person(
   id serial,
   lastname character varying (50),
   firstname character varying (50),
   CONSTRAINT person_pk PRIMARY KEY (id)
);

CREATE TABLE client (
    id integer,
   CONSTRAINT client_pk PRIMARY KEY (id),
   CONSTRAINT fk_client_person FOREIGN KEY (id)
       REFERENCES person (id) MATCH SIMPLE
);

अगर हमें क्लाइंट रिकॉर्ड डालने की आवश्यकता है, तो हमें एक व्यक्ति रिकॉर्ड का उल्लेख करना चाहिए। लेकिन मान लें कि हम PL / pgSQL फ़ंक्शन को तैयार करना चाहते हैं जो क्लाइंट में एक नया रिकॉर्ड सम्मिलित करता है, लेकिन नए व्यक्ति रिकॉर्ड को सम्मिलित करने का भी ध्यान रखता है। उसके लिए, हमें leonbloy के विकल्प 3 की थोड़ी भिन्नता का उपयोग करना चाहिए:

INSERT INTO person(lastname, firstname) 
VALUES (lastn, firstn) 
RETURNING id INTO [new_variable];

ध्यान दें कि दो INTO क्लॉस हैं। इसलिए, PL / pgSQL फ़ंक्शन को इस तरह परिभाषित किया जाएगा:

CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying)
  RETURNS integer AS
$BODY$
DECLARE
   v_id integer;
BEGIN
   -- Inserts the new person record and retrieves the last inserted id
   INSERT INTO person(lastname, firstname)
   VALUES (lastn, firstn)
   RETURNING id INTO v_id;

   -- Inserts the new client and references the inserted person
   INSERT INTO client(id) VALUES (v_id);

   -- Return the new id so we can use it in a select clause or return the new id into the user application
    RETURN v_id;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

अब हम नया डेटा डाल सकते हैं:

SELECT new_client('Smith', 'John');

या

SELECT * FROM new_client('Smith', 'John');

और हमें नवनिर्मित आईडी मिलती है।

new_client
integer
----------
         1

9

उन लोगों के लिए जिन्हें सभी डेटा रिकॉर्ड प्राप्त करने की आवश्यकता है, आप जोड़ सकते हैं

returning *

आईडी सहित सभी ऑब्जेक्ट को प्राप्त करने के लिए अपनी क्वेरी के अंत तक।


8

नीचे दिए गए उदाहरण देखें

CREATE TABLE users (
    -- make the "id" column a primary key; this also creates
    -- a UNIQUE constraint and a b+-tree index on the column
    id    SERIAL PRIMARY KEY,
    name  TEXT,
    age   INT4
);

INSERT INTO users (name, age) VALUES ('Mozart', 20);

तब अंतिम सम्मिलित आईडी के लिए तालिका "उपयोगकर्ता" seq स्तंभ नाम "id" के लिए इसका उपयोग करें

SELECT currval(pg_get_serial_sequence('users', 'id'));

7
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))

आपको पाठ्यक्रम का तालिका नाम और स्तंभ नाम की आपूर्ति करने की आवश्यकता है।

यह वर्तमान सत्र / कनेक्शन के लिए होगा । http://www.postgresql.org/docs/8.3/static/functions-fterence.html


1

इसे इस्तेमाल करे:

select nextval('my_seq_name');  // Returns next value

यदि यह वापसी 1 (या जो भी आपके अनुक्रम के लिए start_value है), तो झूठे ध्वज को पारित करते हुए अनुक्रम को मूल मूल्य पर वापस सेट करें:

select setval('my_seq_name', 1, false);

अन्यथा,

select setval('my_seq_name', nextValue - 1, true);

यह अनुक्रम मान को मूल स्थिति में पुनर्स्थापित करेगा और "सेवल" उस अनुक्रम मान के साथ लौटेगा जिसे आप खोज रहे हैं।


1

Postgres में एक इनबिल्ट मैकेनिज्म है, जो उसी क्वेरी में id देता है या जो भी आप चाहते हैं वह क्वेरी वापस आ जाती है। यहाँ एक उदाहरण है। विचार करें कि आपके पास एक तालिका बनाई गई है जिसमें 2 कॉलम कॉलम 1 और कॉलम 2 हैं और आप चाहते हैं कि कॉलम 1 को हर प्रविष्टि के बाद लौटा दिया जाए।

# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
 id 
----
  1
(1 row)

# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
 id 
----
  2
(1 row)

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