2009-04-08 60 views
75

我一直在尋找一段時間,但我找不到解決我的問題的簡單方法。我想在表中複製一條記錄,但當然,唯一的主鍵需要更新。在同一個MySQL表中複製/複製記錄

我有這個疑問:

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

的問題是,這只是改變了該行的ID而不是複製的行。有人知道如何解決這個問題嗎?

//編輯:我想這樣做而不輸入所有的字段名稱,因爲字段名稱可以隨時間變化。

回答

115

我通常使用的方式是使用臨時表。這可能不是計算效率高,但它似乎工作正常!我在這裏重複記錄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; 

希望對你有用ok了!

+0

我喜歡它,中間要留意一些東西 – SeanDowney 2011-05-04 21:54:26

+3

如果您要複製單個記錄,則可以刪除更新和插入的位置。然後你可以在mysql控制檯中按兩次,這會彈出歷史記錄中的倒數第二個操作,在最後更改方便的update中的id,按回車鍵,按下,再次敲入,而不改變任何內容,然後重複該程序爲多個副本。快多了。 – 2012-03-12 22:57:20

11

你肯定知道,那重複鍵將觸發,所以你可以選擇MAX(ID)+1事先:

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

是的,但我不想輸入所有其他字段(大約有20個字段,它們可能會隨時間而改變)。每當表結構發生變化時,我都不想更改代碼。 – Digits 2009-04-08 11:17:40

+0

你必須。您最好製作一個從字段列表中生成SQL語句的腳本。這是微不足道的。 – Ingo 2009-04-08 11:27:07

+0

唯一的另一種選擇是使用插入觸發器(如果mysql支持的話)。 – Ingo 2009-04-08 11:29:09

1

我需要這個爲好;我的解決方案是使用SQLYOG(免費版)將所需記錄導出爲SQL(創建插入)。

然後,我手編輯這個刪除id,因爲這需要自動生成,然後將插入複製到SQLYog執行它。這是無痛的。我猜大量的其他MySQL GUI也可以做到這一點。

這爲我提供了一個記錄,我可以將它用於實時系統的測試目的。

我現在也有這個插入以供重用,因爲每天都會重寫表。

75

亞歷克斯的回答在多客戶端環境中需要謹慎(例如鎖定或事務)。

假設AUTO ID字段是表中的第一個字段(通常情況下),我們可以使用隱式的 事務。

 
    CREATE TEMPORARY TABLE tmp SELECT * from invoices WHERE ...; 
    ALTER TABLE tmp drop ID; # drop autoincrement field 
    # UPDATE tmp SET ...; # just needed to change other unique keys 
    INSERT INTO invoices SELECT 0,tmp.* FROM tmp; 
    DROP TABLE tmp; 

從MySQL的文檔:

使用AUTO_INCREMENT:您也可以明確地指定NULL或0到列生成的序列號。

2

我有一個類似的問題,這是whant我做

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

去過Preguntas:

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自動遞增,也是我正在使用EncuestaID的固定值('23')

10

您的方法很好,但問題在於您使用「*」代替了註冊字段名稱秒。如果你把所有的列名稱作爲主鍵,你的腳本將像一個或多個記錄上的魅力一樣工作。

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

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; 
1

我只是想延長Alex的偉大答案,使之適宜,如果你碰巧要複製整個一套記錄:

SET @x=7; 
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices; 
UPDATE tmp SET [email protected]; 
INSERT INTO invoices SELECT * FROM tmp; 

我只是要做到這一點,發現亞歷克斯的答案是一個完美的跳躍點!當然,你必須將@x設置爲表格中最高的行數(我相信你可以通過查詢來獲取)。這隻適用於這種非常特殊的情況,所以當你不想複製所有行時要小心使用它。根據需要調整數學。

3

我知道一個遲到的答案,但它仍然是一個常見問題,我想添加另一個答案,它爲我工作,只使用單行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列,否則,您可以添加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; 

它非常簡單直接,您可以在一行中更新其他任何內容,而不需要第二次更新語句以備後用(例如:用額外文本更新標題列或用另一個字符串替換字符串),也可以指定你想要複製什麼,如果全部是這樣的話,如果有的話,你可以這樣做。