DUPLICATE KEY पर MySQL - आखिरी इन्सर्ट आईडी?


132

मेरे पास निम्नलिखित प्रश्न हैं:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE a=1

मुझे या तो इन्सर्ट या अपडेट की आईडी चाहिए। आमतौर पर मैं इसे प्राप्त करने के लिए दूसरी क्वेरी चलाता हूं क्योंकि मेरा मानना ​​है कि Insert_id () केवल 'सम्मिलित' आईडी लौटाता है न कि अपडेट की गई आईडी।

क्या दो प्रश्नों को चलाने के बिना INSERT / UPDATE और पंक्ति की ID पुनः प्राप्त करने का कोई तरीका है?


3
दबाने के बजाय, आप इसे स्वयं क्यों नहीं परखते? ऊपर दिए गए संपादन में एसक्यूएल काम करता है, और मेरे परीक्षण के माध्यम से इन्सर्ट इग्नोर का उपयोग करके एक प्रविष्टि को पकड़ने में विफल होने की तुलना में तेज है, या पहले एक डुप्लिकेट है, यह देखने के लिए चयन करना।
माइकल फेनविक

4
चेतावनी: समाधान प्रस्तावित कार्य करता है, लेकिन कोई प्रविष्टि नहीं होने पर भी स्वतः-मूल्य वृद्धि में वृद्धि जारी रहती है। यदि डुप्लिकेट कुंजी अक्सर होती है, तो आप alter table tablename AUTO_INCREMENT = 0;अपने आईडी मानों में बड़े अंतराल से बचने के लिए उपरोक्त क्वेरी के बाद चलाना चाह सकते हैं ।
फ्रैंक फोर्ट

जवाबों:


175

इस पृष्ठ को देखें: https://web.archive.org/web/20150329004325/https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html पृष्ठ
के नीचे वे बताते हैं कि आप उस MySQL फ़ंक्शन के लिए एक अभिव्यक्ति पास करके अपडेट के लिए LAST_INSERT_ID को कैसे सार्थक बना सकते हैं।

MySQL प्रलेखन उदाहरण से:

यदि किसी तालिका में AUTO_INCREMENT कॉलम और INSERT होता है ... अद्यतन पंक्ति में सम्मिलित होता है, तो LAST_INSERT_ID () फ़ंक्शन AUTO_INCREMENT मान लौटाता है। यदि कथन इसके बजाय किसी पंक्ति को अपडेट करता है, तो LAST_INSERT_ID () सार्थक नहीं है। हालाँकि, आप LAST_INSERT_ID (expr) का उपयोग करके इसके आसपास काम कर सकते हैं। मान लीजिए कि आईडी AUTO_INCREMENT कॉलम है। अपडेट के लिए LAST_INSERT_ID () को सार्थक बनाने के लिए पंक्तियों को निम्नानुसार डालें:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;

2
किसी तरह मैं उस पेज को देखने से चूक गया। तो अद्यतन भाग के रूप में प्रकट होता है: अद्यतन आईडी = LAST_INSERT_ID (आईडी) और यह महान काम करता है। धन्यवाद!
akevinscott

7
ऐसा कहा जाता है कि php फ़ंक्शन mysql_insert_id () दोनों मामलों में सही मान देता है: php.net/manual/en/function.mysql-insert-id.php#59718
जयरोज़ो

2
@PetrPeller - ठीक है, MySQL के इंटर्नल को देखे बिना, इसका शायद मतलब है कि यह एक मूल्य का उत्पादन करेगा, लेकिन यह मूल्य उस क्वेरी से संबंधित नहीं है जिसे आपने अभी चलाया था। दूसरे शब्दों में, एक समस्या जो डीबग करने के लिए एक दर्द है।
जेसन

13
५.१.१२ के बाद यह माना जाता है कि यह अब आवश्यक नहीं है, लेकिन मुझे आज इसका एक अपवाद मिला। यदि आपके पास एक ऑटोइन्क्रिमेशन पीके है, और ईमेल पते के लिए एक अद्वितीय कुंजी है, और ईमेल पते के आधार पर 'डुप्लिकेट अपडेट पर ट्रिगर', ध्यान दें कि last_insert_id 'अपडेटेड पंक्ति का ऑटोइन्क्रिमेंट वैल्यू नहीं होगा। यह सबसे हाल ही में डाला गया ऑटोइन्क्रिमेंट मूल्य प्रतीत होता है। इससे बहुत फर्क पड़ता है। आस-पास का कार्य वही है जो यहां दिखाया गया है, अर्थात् अद्यतन क्वेरी में आईडी = LAST_INSERT_ID (आईडी) का उपयोग करने के लिए।
sckd

1
5.5 @ sckd की टिप्पणी अभी भी सही है।
e18r

37

सटीक होने के लिए, यदि यह मूल प्रश्न है:

INSERT INTO table (a) VALUES (0)
 ON DUPLICATE KEY UPDATE a=1

और 'id' ऑटो-इन्क्रीमेंट प्राइमरी कुंजी है, इससे काम करने वाला समाधान होगा:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1

यहाँ सब है: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplication.html

यदि किसी तालिका में AUTO_INCREMENT कॉलम और INSERT होता है ... अद्यतन पंक्ति में सम्मिलित होता है, तो LAST_INSERT_ID () फ़ंक्शन AUTO_INCREMENT मान लौटाता है। यदि कथन इसके बजाय किसी पंक्ति को अपडेट करता है, तो LAST_INSERT_ID () सार्थक नहीं है। हालाँकि, आप LAST_INSERT_ID (expr) का उपयोग करके इसके आसपास काम कर सकते हैं। मान लीजिए कि आईडी AUTO_INCREMENT कॉलम है।


7
हां, आपने जो कहा, उसके लिए स्वीकृत उत्तर देखें। 3 साल पुराने पदों को पुनर्जीवित करने की आवश्यकता नहीं है। वैसे भी आपके प्रयास के लिए धन्यवाद।
फैंसीपैंट

1
@tombom केवल यही कारण है कि मैंने यह उत्तर पोस्ट किया है क्योंकि स्वीकृत उत्तर सही नहीं है - यह काम नहीं करेगा यदि अपडेट करने के लिए कुछ भी नहीं है।
अलेक्जेंडर पोपोविक 23

2

आप REPLACE को देख सकते हैं, जो रिकॉर्ड मौजूद होने पर अनिवार्य रूप से एक डिलीट / इंसर्ट है। लेकिन यह वर्तमान में ऑटो वेतन वृद्धि क्षेत्र को बदल देगा, जो अन्य डेटा के साथ संबंध तोड़ सकता है।


1
आह हाँ - मैं कुछ ऐसी चीज़
ढूँढ

यह खतरनाक भी हो सकता है क्योंकि इससे दूसरे संबंधित डेटा को हटाने (बाधाओं के कारण) भी हो सकता है।
सर्ज

2

मुझे नहीं पता कि MySQL का आपका संस्करण क्या है, लेकिन InnoDB के साथ, autoinc के साथ बग था

5.1.20 में बग और 5.1.23 में सही किया गया http://bugs.mysql.com/bug.php?id=27405

5.1.31 में बग और 5.1.33 में सही किया गया http://bugs.mysql.com/bug.php?id=42714


1

मुझे एक समस्या आई है, जब ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID (id) प्राथमिक कुंजी को 1 से बढ़ाती है। इसलिए सत्र के भीतर अगले इनपुट की आईडी 2 से बढ़ाई जाएगी।


0

यह ध्यान देने योग्य है, और यह स्पष्ट हो सकता है (लेकिन मैं इसे यहां स्पष्टता के लिए वैसे भी कहूंगा), कि REPLACE आपके नए डेटा को डालने से पहले मौजूदा मिलान पंक्ति को उड़ा देगा। डुप्लिकेट कुंजी पर अद्यतन केवल आपके द्वारा निर्दिष्ट कॉलम को अद्यतन करेगा और पंक्ति को संरक्षित करेगा।

से मैनुअल :

REPLACE बिलकुल INSERT की तरह काम करता है, सिवाय इसके कि अगर तालिका में एक पुरानी पंक्ति में PRIMARY KEY या UNIQUE इंडेक्स के लिए नई पंक्ति के समान मूल्य है, तो नई पंक्ति सम्मिलित होने से पहले पुरानी पंक्ति हटा दी जाती है।


0

मौजूदा समाधान काम करते हैं यदि आप स्वप्रेरक का उपयोग करते हैं। मेरे पास एक ऐसी स्थिति है जहां उपयोगकर्ता एक उपसर्ग को परिभाषित कर सकता है और इसे 3000 पर अनुक्रम को फिर से शुरू करना चाहिए। इस विविध उपसर्ग के कारण, मैं ऑटोइन्क्रिमेंट का उपयोग नहीं कर सकता, जो आवेषण के लिए last_insert_id को खाली करता है। मैंने इसे निम्नलिखित के साथ हल किया:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1);
SELECT LAST_INSERT_ID();

यदि उपसर्ग मौजूद है, तो यह इसे बढ़ाएगा और last_insert_id को पॉप्युलेट करेगा। यदि उपसर्ग मौजूद नहीं है, तो यह उपसर्ग को 3000 मान के साथ सम्मिलित करेगा और 3000 के साथ last_insert_id को आबाद करेगा।

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