SQL सर्वर - INSERT के बाद मान लौटाएं


318

मैं INSERT- स्टेटमेंट के बाद की-वैल्यू वापस पाने की कोशिश कर रहा हूं। उदाहरण: मुझे विशेषता नाम और आईडी के साथ एक तालिका मिली है। आईडी एक उत्पन्न मूल्य है।

    INSERT INTO table (name) VALUES('bob');

अब मैं उसी चरण में आईडी वापस लेना चाहता हूं। यह कैसे किया जाता है?

हम Microsoft SQL Server 2008 का उपयोग कर रहे हैं।


मैं एक उपयोगी जवाब मिली: [preparedstatement-साथ-कथन-रिटर्न-उत्पन्न कुंजी] [1] [1]: stackoverflow.com/questions/4224228/...
लार्स Ladegaard

जवाबों:


477

अलग चयन की कोई आवश्यकता नहीं ...

INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');

यह गैर-पहचान कॉलम (जैसे GUID) के लिए भी काम करता है


29
क्या आप थोड़ा विस्तार कर सकते हैं? इस उदाहरण में आउटपुट कहाँ जाता है? प्रलेखन केवल तालिकाओं के लिए उदाहरण दिखाता है (आउटपुट का उपयोग ... में)। आदर्श रूप में मैं इसे केवल एक चर में बदलने में सक्षम होना चाहता हूं
जॉनी रा'आ

2
@JonnyLeeds: आप इसे एक चर (जब तक तालिका चर नहीं) नहीं कर सकते। OUTPUT क्लाइंट या एक टेबल पर जाता है
gbn

7
दुर्भाग्य से, आप इस पर भरोसा नहीं कर सकते क्योंकि तालिका में एक ट्रिगर जोड़ने से आपके बयान टूट जाएंगे! पुन: blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/…
hajikelist

1
@hajikelist: यह काफी एज केस है, ट्रिगर में SET NCOOUNT ON आमतौर पर मदद करता है। देखें stackoverflow.com/questions/1483732/set-nocount-on-usage
gbn

5
@@ पहचान का उपयोग कभी न करें। SCOPE_IDENTITY, हां, लेकिन कभी भी @@ पहचान नहीं। यह अविश्वसनीय है
gbn

188

SCOPE_IDENTITY()नई आईडी मान प्राप्त करने के लिए उपयोग करें

INSERT INTO table (name) VALUES('bob');

SELECT SCOPE_IDENTITY()

http://msdn.microsoft.com/en-us/library/ms190315.aspx


7
मान्यता idहै
Ilia G

12
@ liho1eye - ओपी ने पहचान कॉलम नाम के रूप में संदर्भित किया id, इसलिए हां।
कर्ट

3
बड़े सिस्टम पर, यदि एक ही समय में कई sql चलते हैं तो क्या होगा? क्या यह हर अनुरोध के लिए अंतिम सम्मिलित आईडी लौटाएगा?
शिव

2
@ शिव "SCOPE_IDENTITY केवल मौजूदा दायरे के भीतर डाले गए मान लौटाता है"
goodies4uall

45
INSERT INTO files (title) VALUES ('whatever'); 
SELECT * FROM files WHERE id = SCOPE_IDENTITY();

ट्रिगर के साथ तालिकाओं पर OUTPUT क्लॉज संघर्ष के साथ एक ज्ञात समस्या होने के बाद से सबसे सुरक्षित शर्त है। इसे काफी अविश्वसनीय बनाता है, भले ही आपकी तालिका में वर्तमान में कोई ट्रिगर नहीं है - कोई व्यक्ति जो नीचे एक पंक्ति जोड़ रहा है, वह आपके एप्लिकेशन को तोड़ देगा। समय बम व्यवहार की तरह।

गहरी व्याख्या के लिए msdn लेख देखें:

http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx


तभी जब आप ट्रिगर्स में SET NOCOUNT ON नहीं जोड़ते हैं। यह भी देखें docs.microsoft.com/en-us/sql/database-engine/configure-windows/...
GBN

यह हमारे विरासत के वातावरण @ जीबीएन
हजिकेलिस्ट

@hajelelist हम सभी के पास विरासत है, लेकिन OUTPUT में गड़बड़ी करने वाले ट्रिगर्स का जोखिम कम है, यह सब लगता है। यदि कोई ट्रिगर जोड़ रहा है, तो उन्हें पता होना चाहिए कि इसे कैसे कोडित करना है (इसका मतलब है कि आपके पास मुख्य रूप से नियंत्रण है), या आपको अपने डेवलपर्स को प्रशिक्षित करने की आवश्यकता है .. कुछ बिंदु पर, आपको उस समय माइग्रेट करने के लिए मजबूर किया जाएगा जब SQL का वह संस्करण नहीं रह गया है ट्रिगर्स का समर्थन किया गया तो परिणाम नहीं होगा। जो भी हो, यह सबसे अच्छा उत्तर नहीं है क्योंकि यदि आपके पास ट्रिगर का INSTEAD है तो SCOPE_IDENTITY काम नहीं कर सकती है ( stackoverflow.com/questions/908257/… )
gbn

@ जीबी - मुझे इस तरह से मूर्खतापूर्ण चीजों से बचना पसंद है। मैं अपने सभी डेवलपर्स को यह बताने नहीं जा रहा हूं, "हर ट्रिगर में 'मेरे ऐप स्टेटमेंट को न तोड़ें' जोड़ना न भूलें।" - तुम इसे रख सकते हो। "बजाय" परिदृश्य एक किनारे के मामले imo के कहीं अधिक है।
हजिकेलिस्ट

एक बार जब यह इस से वापस आ जाता है तो एक सुरक्षित उत्तर के लिए आवेदन को एक और क्वेरी चलाने के लिए हो सकता है। जब तक यह पीछे के छोर पर किया जाता है, प्रदर्शन जुर्माना लोगों के समूहों में विकास के प्रबंधन की सादगी के लायक होना चाहिए, और यह किनारे के मामलों के साथ कुछ पागल विशेषता की तुलना में मानकों के अनुसार करीब है। मैं नहीं बल्कि किनारे के मामले मेरे कोड में होंगे, और प्लेटफ़ॉर्म पर उनसे बचना चाहिए। सिर्फ मेरी राय बाहर नहीं है :)
दान चेस

33

इकाई फ्रेमवर्क gbn के उत्तर के समान कुछ करता है:

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO @generated_keys
VALUES('bob');

SELECT t.[CustomerID]
FROM @generated_keys AS g 
   JOIN dbo.Customers AS t 
   ON g.Id = t.CustomerID
WHERE @@ROWCOUNT > 0

आउटपुट परिणाम एक अस्थायी तालिका चर में संग्रहीत किए जाते हैं, और फिर ग्राहक को वापस चुना जाता है। गोत्र से अवगत होना है:

आवेषण एक से अधिक पंक्ति उत्पन्न कर सकता है, इसलिए चर एक पंक्ति से अधिक पकड़ सकता है, इसलिए आपको एक से अधिक लौटाया जा सकता है ID

मुझे इस बात का कोई अंदाजा नहीं है कि ईएफ आंतरिक तालिका में वास्तविक तालिका में क्यों शामिल होगा (किन परिस्थितियों में मैच नहीं होगा)।

लेकिन यही ईएफ करता है।

SQL Server 2008 या केवल नया। अगर यह 2005 है तो आप भाग्य से बाहर हैं।


2
ईएफ ऐसा करने का कारण यह सुनिश्चित करता है कि सम्मिलित Customerरिकॉर्ड के अन्य सभी परिवर्तनों को "देख" भी सकता है, क्योंकि अन्य डीबी-साइड लॉजिक इसे प्रभावित कर सकता है, जैसे DEFAULTकुछ कॉलम पर, तालिका पर ट्रिगर, आदि ईएफ अपडेट। इकाई (ऑब्जेक्ट) यह डालने के लिए उपयोग किया जाता है, इसलिए ग्राहक पक्ष को आईडी के साथ ग्राहक वस्तु मिलती है और बाकी सब कुछ पंक्ति की वर्तमान स्थिति का प्रतिनिधित्व करता है।
प्रात

EF का उपयोग नहीं करने का एक और कारण।
cskwg

11

@@IDENTITY एक सिस्टम फ़ंक्शन है जो अंतिम-सम्मिलित पहचान मान लौटाता है।


4
@@ पहचान का उपयोग करने के खिलाफ कभी भी सलाह दें - यह सही (बहुत व्यापक) बहुत कम धागा-सुरक्षित नहीं है - कृपया SCOPE_IDENTITY () के बारे में @ कर्ट का जवाब देखें।
zanlok

10

डालने के बाद बाहर निकलने के कई तरीके हैं

जब आप किसी तालिका में डेटा सम्मिलित करते हैं, तो आप तालिका में डाली गई डेटा की एक प्रति वापस करने के लिए OUTPUT क्लॉज़ का उपयोग कर सकते हैं। OUTPUT क्लॉज दो मूल रूप लेता है: OUTPUT और OUTPUT INTO। यदि आप कॉलिंग एप्लिकेशन को डेटा वापस करना चाहते हैं तो OUTPUT फॉर्म का उपयोग करें। यदि आप डेटा को किसी तालिका या टेबल चर पर लौटना चाहते हैं, तो OUTPUT INTO फॉर्म का उपयोग करें।

DECLARE @MyTableVar TABLE (id INT,NAME NVARCHAR(50));

INSERT INTO tableName
(
  NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO @MyTableVar
VALUES
(
   'test',...
)

IDENT_CURRENT : यह किसी विशेष सत्र या किसी सत्र में देखने के लिए बनाई गई अंतिम पहचान देता है।

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]

SCOPE_IDENTITY : यह एक ही सत्र और समान दायरे से अंतिम पहचान देता है। एक स्कोप एक संग्रहीत प्रक्रिया / ट्रिगर आदि है।

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  

@@ पहचान : यह एक ही सत्र से अंतिम पहचान देता है।

SELECT @@IDENTITY AS [@@IDENTITY];

1
@RezaJenabi Jun, आउट पुट बहुत अच्छा काम किया है, तालिका में कई आईडी खोजने से बेहतर है। मैंने इसके out putलिए उपयोग किया bulk insertऔर डाला select statement। आपके सुझाव का शुक्रिया
अमीरहोसिन

5

सबसे अच्छा और सबसे निश्चित समाधान उपयोग कर रहा है SCOPE_IDENTITY()

बस आपको हर इंसर्ट के बाद स्कोप आइडेंटिटी प्राप्त करनी होगी और उसे एक वैरिएबल में सेव करना होगा क्योंकि आप एक ही स्कोप में दो इंसर्ट कह सकते हैं।

ident_currentऔर @@identityवे काम कर सकते हैं, लेकिन वे सुरक्षित गुंजाइश नहीं हैं। आपके पास एक बड़े एप्लिकेशन में समस्याएँ हो सकती हैं

  declare @duplicataId int
  select @duplicataId =   (SELECT SCOPE_IDENTITY())

अधिक विस्तार यहाँ Microsoft डॉक्स है


1
इसे सरल कर सकते हैंselect @duplicataId = SCOPE_IDENTITY()
पीसीएन करें

1
OUTPUTक्लॉज एक बेहतर, अधिक शुद्ध समाधान है :)
Dale K

OUTPUT INTO बहुत धीमा है।
cskwg

4

आप scope_identity()केवल एक चर में डाली गई पंक्ति की आईडी का चयन करने के लिए उपयोग कर सकते हैं, फिर उस तालिका से जो भी कॉलम चाहते हैं उसका चयन करें जहां आईडी = पहचान आपको मिली है।scope_identity()

MSDN जानकारी के लिए यहाँ देखें http://msdn.microsoft.com/en-us/library/ms190315.aspx


1

इन्सर्ट कमांड के बाद अंतिम सम्मिलित आईडी प्राप्त करने के कई तरीके हैं।

  1. @@IDENTITY : यह मौजूदा सत्र में एक कनेक्शन पर उत्पन्न अंतिम पहचान मूल्य लौटाता है, भले ही मूल्य का उत्पादन करने वाले तालिका और बयान के दायरे की परवाह किए बिना
  2. SCOPE_IDENTITY(): यह मौजूदा संबंध में वर्तमान विवरण में तालिका की परवाह किए बिना सम्मिलित विवरण द्वारा उत्पन्न अंतिम पहचान मूल्य लौटाता है।
  3. IDENT_CURRENT(‘TABLENAME’): यह किसी भी कनेक्शन, सत्र या दायरे की परवाह किए बिना निर्दिष्ट तालिका पर उत्पन्न अंतिम पहचान मूल्य देता है। IDENT_CURRENT गुंजाइश और सत्र तक सीमित नहीं है; यह एक निर्दिष्ट तालिका तक सीमित है।

अब यह तय करना अधिक कठिन है कि मेरी आवश्यकता के लिए कौन सा मैच सटीक होगा।

मैं ज्यादातर SCOPE_IDENTITY () पसंद करता हूं।

यदि आप सम्मिलित विवरण में TableName के साथ SCOPE_IDENTITY () का उपयोग करते हैं, तो आपको उनकी अपेक्षा के अनुसार सटीक परिणाम मिलेगा।

स्रोत: कोडोबी


0

SQL सर्वर में पहचान कॉलम के रूप में ID का उपयोग करने वाली तालिका में सम्मिलित करते समय, मैं इस तरह से बाहर का उपयोग करता हूं:

'myConn is the ADO connection, RS a recordset and ID an integer
Set RS=myConn.Execute("INSERT INTO M2_VOTELIST(PRODUCER_ID,TITLE,TIMEU) OUTPUT INSERTED.ID VALUES ('Gator','Test',GETDATE())")
ID=RS(0)

0

आप अपने सम्मिलित विवरण में एक चुनिंदा विवरण जोड़ सकते हैं। पूर्णांक myInt = तालिका 1 में डालें (FName) मान ('फ्रेड'); Scope_Identity () का चयन करें; यह स्केलर को निष्पादित करने पर पहचान का एक मूल्य लौटाएगा।


-4

एक पहचान स्तंभ के साथ एक तालिका में एक प्रविष्टि करने के बाद, आप मूल्य प्राप्त करने के लिए @@ पहचान को संदर्भित कर सकते हैं: http://msdn.microsoft.com/en-us/library/aa933167%28v=sql.80%29.aspx


24
कभी भी @@ पहचान का उपयोग न करें: यह गुंजाइश सुरक्षित नहीं है: ट्रिगर आदि इसे प्रभावित करते हैं।
gbn

-4

* कनेक्शन स्ट्रिंग में पैरामीटर क्रम कभी-कभी महत्वपूर्ण होता है। * प्रदाता पैरामीटर का स्थान एक पंक्ति जोड़ने के बाद रिकॉर्डसेट कर्सर को तोड़ सकता है। हमने SQLOLEDB प्रदाता के साथ इस व्यवहार को देखा।

एक पंक्ति जोड़ने के बाद, पंक्ति फ़ील्ड उपलब्ध नहीं हैं, UNLESS प्रदाता को कनेक्शन स्ट्रिंग में पहले पैरामीटर के रूप में निर्दिष्ट किया गया है । जब प्रदाता पहले पैरामीटर को छोड़कर कनेक्शन स्ट्रिंग में कहीं भी होता है, तो नई सम्मिलित पंक्ति फ़ील्ड उपलब्ध नहीं होती हैं। जब हमने प्रदाता को पहले पैरामीटर पर स्थानांतरित किया, तो पंक्ति फ़ील्ड जादुई रूप से प्रकट हुईं।


1
क्या आप हमें बता सकते हैं कि यह टिप्पणी कैसे उत्तर देती है / उस प्रश्न के लिए प्रासंगिक है जो पूछा गया था? मुझे नहीं लगता कि यह कैप / बोल्ड की हकदार है। यदि आपका उत्तर सहायक माना जाता है, तो उपयोगकर्ता इसे वोट करेंगे।
n__o

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

आपको अपना उत्तर संपादित करने और सुधारने की आवश्यकता है। यह वर्तमान में शोर है और एक सभ्य जवाब या यहां तक ​​कि एक प्रयास के रूप में नहीं आता है
जेम्स

"शोर" से आपका वास्तव में क्या मतलब है? आपको अपनी शिकायत बताने की जरूरत है। यह जितना आसान हो सकता है। यदि आप अपने कनेक्शन स्ट्रिंग में मापदंडों के क्रम को बदलते हैं, तो यह प्रभावित कर सकता है कि पंक्ति डेटा सम्मिलित करने के बाद उपलब्ध है या नहीं।
डेविड गाईडोस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.