एक ही MySQL तालिका में डुप्लिकेट / कॉपी रिकॉर्ड


87

मैं अभी कुछ समय के लिए देख रहा हूं लेकिन मुझे अपनी समस्या का आसान समाधान नहीं मिल रहा है। मैं एक तालिका में एक रिकॉर्ड की नकल करना चाहूंगा, लेकिन निश्चित रूप से, अद्वितीय प्राथमिक कुंजी को अद्यतन करने की आवश्यकता है।

मेरे पास यह प्रश्न है:

INSERT INTO invoices
    SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX
    ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices)

समस्या यह है कि यह केवल IDपंक्ति को कॉपी करने के बजाय पंक्ति को बदलता है । क्या कोई जनता है कि यह कैसे ठीक किया जाता है ?

// संपादित करें: मैं सभी फ़ील्ड नामों को टाइप किए बिना ऐसा करना चाहूंगा क्योंकि फ़ील्ड के नाम समय के साथ बदल सकते हैं।

जवाबों:


137

जिस तरह से मैं आमतौर पर इसके बारे में जाता हूं वह एक अस्थायी तालिका का उपयोग कर रहा है। यह शायद कम्प्यूटेशनल रूप से कुशल नहीं है लेकिन यह ठीक काम करने लगता है! यहां मैं रिकॉर्ड 99 को उसकी संपूर्णता में दोहरा रहा हूं, जिससे वह रिकॉर्ड 100 बना रहा है।

CREATE TEMPORARY TABLE tmp SELECT * FROM invoices WHERE id = 99;

UPDATE tmp SET id=100 WHERE id = 99;

INSERT INTO invoices SELECT * FROM tmp WHERE id = 100;

आशा है कि आप के लिए ठीक काम करता है!


मुझे यह पसंद है, चीजों पर नज़र रखने के लिए बीच में एक कदम
शॉनडाउन

4
यदि आप एक एकल रिकॉर्ड की प्रतिलिपि बना रहे हैं तो आप अपडेट और इंसर्ट दोनों में कहां छोड़ सकते हैं। तब आप mysql कंसोल में केवल दो बार दबा सकते थे जो इतिहास में अगले से अंतिम ऑपरेशन को लाएगा, अपडेट में आईडी को बदल दें जो अंत में सुविधाजनक हो, हिट दर्ज करें, दबाएं, कुछ भी बदले बिना फिर से दर्ज करें, फिर दोहराएं कई प्रतियों के लिए प्रक्रिया। काफी तेज।
क्रिस्टियन व्राबी

4
क्या होगा जब आईडी 100 पहले से ही है। दूसरी बात यह है कि यदि आप अपनी नई पंक्ति के लिए कोई नई आईडी चुनते हैं, और संचालन के दौरान कोई और नई पंक्ति सम्मिलित करता है और फिर आपकी आईडी और नई सम्मिलित आईडी समान होगी। इस कोड में बोतल की गर्दन है।
nbhatti2001

6
आप NULL का उपयोग कर सकते हैं:CREATE TEMPORARY TABLE tmp SELECT bla FROM invoices WHERE bla; UPDATE tmp SET id=NULL; INSERT INTO invoices SELECT * FROM tmp;
Tobias Beuving

1
@TobiasBeuving वह कॉपी-पेस्ट की गई त्रुटि संदेश है क्योंकि मैंने NOT NULLसेट किया है id। मैं सोच रहा था कि क्या आपके पास इस मामले के लिए सुझाव हैं। क्या इसे बुरा व्यवहार माना जाता है?
मार्सेल

84

मल्टी-क्लाइंट वातावरण में एलेक्स के जवाब को कुछ देखभाल (जैसे लॉकिंग या एक लेनदेन) की आवश्यकता होती है।

मान लिया जाए AUTO IDकि तालिका में तालिका पहली (एक सामान्य मामला) है, हम निहित लेनदेन का उपयोग कर सकते हैं।

    इनवॉइस से TEMPORARY TABLE Tmp का चयन करें * ...;
    टेटर टैम्प ड्रॉप आईडी; # ड्रॉप ऑटोइन्क्रिमेंट फ़ील्ड
    # UPDATE tmp SET ...; # बस अन्य अद्वितीय कुंजियों को बदलने की आवश्यकता है
    INSERT में चालान का चयन करें 0, tmp। * Tmp से;
    ड्रॉप टेबल;

MySQL डॉक्स से:

AUTO_INCREMENT का उपयोग करना: आप अनुक्रम संख्या उत्पन्न करने के लिए कॉलम में NULL या 0 भी स्पष्ट रूप से निर्दिष्ट कर सकते हैं।


इसने मेरे लिए एक AUTO_INCREMENT क्षेत्र होते हुए भी रिकॉर्ड को 0 की आईडी के साथ रखा। इसे बदलने के लिए अशक्त काम किया है, इसलिए मैं सुझाव देता हूं कि आप 0. I के बजाय MySQL 5.5.35 (उबंटू) पर हूं।
टायलर कोलियर

@ टायलर कोलियर: NULLया 0दोनों स्वीकार्य हैं। क्या आप पुन: पेश करके मुद्दे के स्क्रीन शॉट्स पोस्ट कर सकते हैं और इसे यहां साझा कर सकते हैं।
रविन्दर रेड्डी

मेरे मस्तिष्क को लाइन 4 में साफ सुथरी समझने की कोशिश में चोट लगी है। शायद यह स्पष्टीकरण मदद करता है: गंतव्य तालिका invoicesमें AUTO_INCREMENT IDफ़ील्ड शामिल है। स्रोत तालिका tmpनहीं है। सम्मिलित करने के दौरान आवश्यक 1: 1 सहसंबंध प्राप्त करने के लिए, आप 0चयन के पहले क्षेत्र के रूप में निर्दिष्ट करते हैं जो गंतव्य तालिका का AUTO_INCREMENT फ़ील्ड है। tmp.*स्रोत तालिका से सभी फ़ील्ड का चयन करता है tmp। उत्तम! अब आपके पास आपका 1: 1 सहसंबंध है। बहुत बढ़िया जवाब @Tim।
elbowlobstercowstand

@RavinderReddy NULL और 0 समान नहीं हैं - 0 का रिकॉर्ड-आईडी होना संभव है - इस तरह की चीज़ के लिए NULL का उपयोग करें
Tobias Beuving

@TobiasBeuving : मैं अच्छी तरह से जानता हूँ कि NULLऔर 0समान नहीं हैं। वर्तमान संदर्भ AUTO_INCREMENTसुविधा पर है। आप ऐसे फ़ील्ड्स में मान 0या NULLमूल्य नहीं डाल सकते हैं। लेकिन जब आप उन्हें ऐसे क्षेत्र में इनपुट के रूप में उपयोग करते हैं, तो अगले अनुक्रम मान को उस क्षेत्र ऑटो मैटिक को सौंपा जाएगा । और इसलिए मेरी टिप्पणी। एसक्यूएल फिडेल
रविन्दर रेड्डी

12

आप निश्चित रूप से जानते हैं, कि DUPLICATE कुंजी ट्रिगर हो जाएगी, इस प्रकार आप MAX (ID) +1 को पहले से ही चुन सकते हैं:

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 

2
हां, लेकिन मैं अन्य सभी क्षेत्रों को टाइप नहीं करना चाहता (कम या ज्यादा 20 हैं, और वे समय के साथ बदल सकते हैं)। मैं हर बार टैबलस्ट्रक्चर में बदलाव के लिए कोड को बदलना नहीं चाहता।
अंक

तुमको करना होगा। आप बेहतर स्क्रिप्ट बनाते हैं जो SQL कथन को फ़ील्ड की सूची से उत्पन्न करता है। यह तुच्छ है।
इंगो

एकमात्र अन्य विकल्प एक सम्मिलित ट्रिगर का उपयोग करना है (यदि mysql उस का समर्थन करता है)।
इंगो

11

आपका दृष्टिकोण अच्छा है लेकिन समस्या यह है कि आप फ़ील्ड नामों को सूचीबद्ध करने के बजाय "*" का उपयोग करते हैं। यदि आप सभी स्तंभों को नाम देते हैं तो प्राथमिक कुंजी को हटा दें आपकी स्क्रिप्ट एक या कई रिकॉर्ड पर आकर्षण की तरह काम करेगी।

INSERT INTO invoices (iv.field_name, iv.field_name,iv.field_name ) SELECT iv.field_name, iv.field_name,iv.field_name FROM invoices AS iv WHERE iv.ID=XXXXX


हालाँकि इसका मतलब यह है कि जैसे ही कोई फ़ील्ड टेबल से जोड़ा या गिराया जाता है, आपको कोड बदलना होगा, जिसे मैं व्यक्तिगत रूप से एक MAJOR no-no के रूप में देखता हूं। (हमेशा नहीं, लेकिन अक्सर पर्याप्त।)
रोमर

10

एक देर से जवाब जो मुझे पता है, लेकिन यह अभी भी एक सामान्य सवाल है, मैं एक और जवाब जोड़ना चाहूंगा कि यह मेरे लिए काम करता है, केवल एक लाइन insert intoस्टेटमेंट का उपयोग करने के साथ , और मुझे लगता है कि यह सीधा है, बिना कोई नई तालिका बनाए (क्योंकि यह हो सकता है) CREATE TEMPORARY TABLEअनुमति के साथ एक मुद्दा हो ):

INSERT INTO invoices (col_1, col_2, col_3, ... etc)
  SELECT
    t.col_1,
    t.col_2,
    t.col_3,
    ...
    t.updated_date,
  FROM invoices t;

AUTO_INCREMENTआईडी कॉलम के लिए समाधान काम कर रहा है , अन्यथा, आप IDस्टेटमेंट में कॉलम भी जोड़ सकते हैं :

INSERT INTO invoices (ID, col_1, col_2, col_3, ... etc)
  SELECT
    MAX(ID)+1,
    t.col_1,
    t.col_2,
    t.col_3,
    ... etc ,
  FROM invoices t;

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


2
नकल करते समय कुछ क्षेत्रों को संशोधित करने के लिए यह एक अच्छा आधार भी है। मैं केवल INSERT into wp_options SELECT NULL, 'theme_mods_twopress', option_value, autoload FROM wp_options where option_name = 'theme_mods_onepress';प्रविष्टि ( AUTO_INCREMENT NULLऊपर से चाल) और option_nameसाथ ही फ़ील्ड को बढ़ाते समय कॉपी करता था।
मार्सेल वाल्डवोगेल

हाँ .. मेरे लिए अच्छा विचार है। धन्यवाद!!
रागु नटराजन

सबसे अच्छा समाधान
एरलन चार्ल्स

3

मैं सिर्फ एलेक्स के शानदार उत्तर को विस्तारित करना चाहता था, ताकि यदि आप रिकॉर्ड के एक पूरे सेट को डुप्लिकेट करना चाहते हैं तो यह उचित हो सके:

SET @x=7;
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices;
UPDATE tmp SET id=id+@x;
INSERT INTO invoices SELECT * FROM tmp;

मुझे बस यही करना था और एलेक्स के जवाब को एक सटीक जम्पिंग पॉइंट बताया। बेशक, आपको तालिका में सर्वोच्च पंक्ति संख्या में @ x सेट करना होगा (मुझे यकीन है कि आप इसे क्वेरी के साथ पकड़ सकते हैं)। यह केवल इस विशिष्ट स्थिति में उपयोगी है, इसलिए जब आप सभी पंक्तियों की नकल नहीं करना चाहते हैं, तो इसका उपयोग करना सावधान रहें। गणित को आवश्यकतानुसार समायोजित करें।


2

मेरे पास एक समान मुद्दा है, और यही मैं कर रहा हूं:

insert into Preguntas  (`EncuestaID`, `Tipo` , `Seccion` , `RespuestaID` , `Texto` )  select '23', `Tipo`, `Seccion`, `RespuestaID`, `Texto` from Preguntas where `EncuestaID`= 18

बन गया है

CREATE TABLE IF NOT EXISTS `Preguntas` (
  `ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `EncuestaID` int(11) DEFAULT NULL,
  `Tipo` char(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  `Seccion` int(11) DEFAULT NULL,
  `RespuestaID` bigint(11) DEFAULT NULL,
  `Texto` text COLLATE utf8_unicode_ci ,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=522 ;

तो, IDस्वचालित रूप से वृद्धि हुई है और इसके लिए मैं एक निश्चित मूल्य ('23') का उपयोग कर रहा हूं EncuestaID


क्षमा करें, मुझे बस एहसास हुआ कि आप कॉलम नाम का उपयोग नहीं करना चाहते, इसलिए यह लागू नहीं होता
एलेक्स एंजेलिको

1

मुझे इसकी भी आवश्यकता थी; मेरा समाधान SQL के रूप में वांछित रिकॉर्ड निर्यात करने के लिए SQLYOG (मुक्त संस्करण) का उपयोग करना था (एक सम्मिलित बनाता है)।

फिर मैंने आईडी को हटाने के लिए इसे संपादित किया क्योंकि इसे ऑटो-जनरेट करने की आवश्यकता है और फिर इसे निष्पादित करने के लिए SQLYog में सम्मिलित कॉपी किया। यह दर्द रहित था। मुझे लगता है कि अन्य MySQL GUIs भी ऐसा कर सकते हैं।

यह मुझे एक रिकॉर्ड के साथ प्रदान करता है जिसका उपयोग मैं लाइव सिस्टम पर परीक्षण उद्देश्यों के लिए कर सकता हूं।

मेरे पास अब यह पुन: उपयोग के लिए सम्मिलित है, साथ ही तालिका को फिर से लिखा गया है।


0

थोड़ा भिन्नता, प्राथमिक कुंजी फ़ील्ड ("varname") को अशक्त करने के लिए सेट किया जा रहा मुख्य अंतर, जो चेतावनी देता है लेकिन काम करता है। प्राथमिक कुंजी को शून्य करने के लिए, अंतिम विवरण में रिकॉर्ड सम्मिलित करते समय ऑटो-इंक्रीमेंट काम करता है।

यह कोड पिछले प्रयासों को भी साफ करता है, और समस्याओं के बिना एक से अधिक बार चलाया जा सकता है:

DELETE FROM `tbl` WHERE varname="primary key value for new record";
DROP TABLE tmp;
CREATE TEMPORARY TABLE tmp SELECT * FROM `tbl` WHERE varname="primary key value for old record";
UPDATE tmp SET varname=NULL;
INSERT INTO `tbl` SELECT * FROM tmp;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.