วิธีการคัดลอกแถวและแทรกในตารางเดียวกันกับเขตข้อมูล autoincrement ใน MySQL?


233

ใน MySQL ฉันพยายามที่จะคัดลอกแถวที่มีautoincrement column ID=1และใส่column ID=2ข้อมูลลงในตารางเดียวกันเป็นแถวใหม่ที่มี

ฉันจะทำสิ่งนี้ในแบบสอบถามเดียวได้อย่างไร

คำตอบ:


351

การใช้INSERT ... SELECT:

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

ที่มีคอลัมน์ทั้งหมดยกเว้นc1, c2, ... idหากคุณต้องการแทรกด้วยid2 อย่างชัดเจนให้รวมไว้ในรายการคอลัมน์ INSERT และ SELECT ของคุณ:

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

คุณจะต้องดูแลซ้ำid2 ที่เป็นไปได้ในกรณีที่สองแน่นอน


1
คุณสามารถหาชื่อของคอลัมน์โดยใช้ INFORMATION_SCHEMA ... ฉันสงสัยว่าคุณสามารถทำมันเป็นแบบสอบถามย่อยและฟังก์ชั่นสตริงได้ไหม? อืม ...
Yzmir Ramirez

1
@Yzmir: คุณต้องใช้ SQL แบบไดนามิกและต้องสร้างกระบวนงานที่เก็บไว้ ดูเหมือนว่ามีปัญหามากกว่าที่ควรค่าเมื่อคุณควรมีรายการชื่อคอลัมน์ที่มีประโยชน์อยู่ดี
mu สั้นเกินไป

6
ตกลง ... จากประสบการณ์ของฉันเมื่อคุณไปที่ขั้นตอนการจัดเก็บคุณจะไม่ย้อนกลับ - คุณแต่งงานกับฐานข้อมูลนั้นแล้วและเพิ่มค่าใช้จ่ายเมื่อใดก็ตามที่คุณต้องการเปลี่ยน
Yzmir Ramirez

11
@YzmirRamirez คุณทำให้ดูเหมือนว่าการแต่งงานเป็นสิ่งที่เลวร้าย :)
ศ. Falken

1
วิธีเพิ่มค่าที่กำหนดเองหนึ่งค่าในคอลัมน์ที่มีเขตข้อมูลที่คัดลอกอื่นทั้งหมดได้อย่างไร
Manish Kumar

49

IMO ที่ดีที่สุดดูเหมือนจะใช้คำสั่ง sql เพื่อคัดลอกแถวนั้นในขณะที่ในเวลาเดียวกันเท่านั้นอ้างอิงคอลัมน์ที่คุณต้องและต้องการเปลี่ยน

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

SELECT * FROM your_table WHERE id=1;
UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;

ดูเพิ่มเติมที่av8n.com - วิธีโคลนบันทึก SQL

ประโยชน์ที่ได้รับ:

  • คำสั่ง SQL 2 กล่าวถึงเฉพาะฟิลด์ที่จำเป็นต้องเปลี่ยนระหว่างกระบวนการโคลน พวกเขาไม่ทราบเกี่ยวกับ - หรือสนใจ - สาขาอื่น ๆ สาขาอื่น ๆ เพียงขี่ไปโดยไม่เปลี่ยนแปลง สิ่งนี้ทำให้คำสั่ง SQL ง่ายต่อการเขียนอ่านง่ายขึ้นง่ายต่อการดูแลรักษาและเพิ่มความสามารถได้มากขึ้น
  • ใช้คำสั่ง MySQL ทั่วไปเท่านั้น ไม่จำเป็นต้องใช้เครื่องมือหรือภาษาการเขียนโปรแกรมอื่น
  • เร็กคอร์ดที่ถูกต้องทั้งหมดถูกแทรกในyour_tableการดำเนินการอะตอมมิกเดียว

3
มันตะเข็บว่าเคล็ดลับดีนี้ (ฉันชอบ แต่ไม่ได้ผลสำหรับฉัน) ไม่ทำงานบนตารางที่มีคอลัมน์ TEXT / VARCHAR ฉันลองแล้วได้: (1163): ประเภทตารางที่ใช้ไม่รองรับคอลัมน์ BLOB / TEXT แน่นอนว่าการ จำกัด การใช้งานบน MySQL เป็นอย่างมาก! อาจเป็นไปได้ว่าในอนาคตข้อ จำกัด เหล่านี้จะถูกยกขึ้นหรือในระบบฐานข้อมูลอื่นมันสามารถใช้งานได้ แต่ตอนนี้มันมีข้อ จำกัด จริงๆ
Juergen

ฉันชอบการใช้ตารางชั่วคราวอย่างชาญฉลาด มีประโยชน์มากสำหรับตารางที่มีคอลัมน์มากมาย!
Lasma

1
หน้าตาดี แต่เมื่อฉันเรียกใช้แบบสอบถามเป็นครั้งแรกใน MySQL, Error Code: 1113. A table must have at least 1 columnฉันได้รับ
ทางกายภาพ

3
คำตอบที่ดีที่สุดสำหรับคอลัมน์จำนวนมาก แต่อาจก่อให้เกิดข้อผิดพลาดSET id=NULL Column 'id' cannot be nullควรแทนที่ด้วยUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder

1
@ ฟิสิคัลการดึงข้อมูลคุณจำเป็นต้องตรวจสอบให้แน่ใจว่าสองบรรทัดแรกเป็นคำสั่งเดียว
ซามูไร

16

user(id, user_name, user_email)บอกว่าตารางเป็น

คุณสามารถใช้แบบสอบถามนี้:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)

29
คุณควรเสมอระบุชื่อคอลัมน์เมื่อใช้ INSERT มิฉะนั้นคุณจะได้รับข้อบกพร่องที่แปลกและน่าสนใจเมื่อมีการเปลี่ยนแปลงแบบแผน
mu สั้นเกินไป

2
แปลกและน่าสนใจอย่างแน่นอน : D
sparkyShorts

ไม่ทำงานกับ sqlite Result: near "SELECT": syntax error
kyb

10

สิ่งนี้ช่วยและสนับสนุนคอลัมน์ BLOB / TEXT

CREATE TEMPORARY TABLE temp_table
AS
SELECT * FROM source_table WHERE id=2;
UPDATE temp_table SET id=NULL WHERE id=2;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY TABLE temp_table;
USE source_table;

นี่เป็นวิธีที่ดีกว่าคำตอบอื่น ๆ ที่นี่?
Smar

3
ฉันคิดว่ามันค่อนข้างดีถ้าคุณมีตารางที่มี 100 ฟิลด์ ยกเว้นอาจจะมีข้อ จำกัด ที่ไม่เป็นโมฆะใน id ซึ่งทำให้มันล้มเหลว
Loïc Faure-Lacroix

รหัสข้อผิดพลาด: 1136 การนับคอลัมน์ไม่ตรงกับการนับค่าที่แถว 1
Oleksii Kyslytsyn

นี่จะดีกว่ามากถ้าคุณมีตารางที่มีคอลัมน์ 100s
Tyler S. Loeper

นี่ไม่ใช่สิ่งที่ parvus พูดเมื่อหลายปีก่อนใช่มั้ย
ToolmakerSteve

7

สำหรับวิธีแก้ปัญหาที่รวดเร็วและสะอาดซึ่งไม่ต้องการให้คุณตั้งชื่อคอลัมน์คุณสามารถใช้คำสั่งที่เตรียมไว้ตามที่อธิบายไว้ที่นี่: https://stackoverflow.com/a/23964285/292677

หากคุณต้องการโซลูชันที่ซับซ้อนเพื่อให้คุณสามารถทำได้บ่อยครั้งคุณสามารถใช้ขั้นตอนนี้:

DELIMITER $$

CREATE PROCEDURE `duplicateRows`(_schemaName text, _tableName text, _whereClause text, _omitColumns text)
SQL SECURITY INVOKER
BEGIN
  SELECT IF(TRIM(_omitColumns) <> '', CONCAT('id', ',', TRIM(_omitColumns)), 'id') INTO @omitColumns;

  SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns 
  WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,@omitColumns) = 0 ORDER BY ORDINAL_POSITION INTO @columns;

  SET @sql = CONCAT('INSERT INTO ', _tableName, '(', @columns, ')',
  'SELECT ', @columns, 
  ' FROM ', _schemaName, '.', _tableName, ' ',  _whereClause);

  PREPARE stmt1 FROM @sql;
  EXECUTE stmt1;
END

คุณสามารถรันด้วย:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

ตัวอย่าง

duplicateRows('acl', 'users', 'WHERE id = 200'); -- will duplicate the row for the user with id 200
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts'); -- same as above but will not copy the created_ts column value    
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts,updated_ts'); -- same as above but also omits the updated_ts column
duplicateRows('acl', 'users'); -- will duplicate all records in the table

การปฏิเสธความรับผิด: วิธีนี้มีไว้สำหรับคนที่จะทำซ้ำแถวในตารางจำนวนมากบ่อยครั้ง มันอาจเป็นอันตรายในมือของผู้ใช้อันธพาล


3

นอกจากนี้คุณยังสามารถส่งผ่านใน '0' เป็นค่าสำหรับคอลัมน์เพื่อเพิ่มโดยอัตโนมัติค่าที่ถูกต้องจะถูกใช้เมื่อสร้างระเบียน นี่ง่ายกว่าตารางชั่วคราวมาก

ที่มา: การ คัดลอกแถวใน MySQL (ดูความคิดเห็นที่สองโดย TRiG เพื่อแก้ปัญหาแรกโดยตำนาน)


1
วิธีนี้ใช้ได้กับ MySQL เวอร์ชั่นใหม่กว่าเมื่อ NULL ไม่ยอมรับ
err

3

คำตอบที่ดีมากมายที่นี่ ด้านล่างนี้เป็นตัวอย่างของกระบวนงานที่เก็บไว้ที่ฉันเขียนเพื่อทำงานนี้ให้สำเร็จสำหรับ Web App ที่ฉันกำลังพัฒนา:

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

-- Create Temporary Table
SELECT * INTO #tempTable FROM <YourTable> WHERE Id = Id

--To trigger the auto increment
UPDATE #tempTable SET Id = NULL 

--Update new data row in #tempTable here!

--Insert duplicate row with modified data back into your table
INSERT INTO <YourTable> SELECT * FROM #tempTable

-- Drop Temporary Table
DROP TABLE #tempTable

ในรุ่นปัจจุบันของการตั้งค่า MariaDB / MySQL id = null ให้ # 1048 - คอลัมน์ 'id' ไม่สามารถเป็น null ได้การตั้งค่า id = 0 ทำงาน
shelbypereira

2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

3
นี่เป็นวิธีที่ดีกว่าคำตอบอื่น ๆ ที่นี่?
Smar

1
@smar imo ทำความเข้าใจให้ดี
Satbir Kira

2

หากคุณสามารถใช้ MySQL Workbench คุณสามารถทำได้โดยคลิกขวาที่แถวและเลือก 'คัดลอกแถว' จากนั้นคลิกขวาที่แถวว่างแล้วเลือก 'วางแถว' จากนั้นเปลี่ยน ID แล้ว คลิก 'สมัคร'

คัดลอกแถว:

ป้อนคำอธิบายรูปภาพที่นี่

วางแถวที่คัดลอกลงในแถวว่าง:

ป้อนคำอธิบายรูปภาพที่นี่

เปลี่ยน ID:

ป้อนคำอธิบายรูปภาพที่นี่

สมัคร:

ป้อนคำอธิบายรูปภาพที่นี่


0

ฉันกำลังมองหาคุณสมบัติเดียวกัน แต่ฉันไม่ได้ใช้ MySQL ฉันต้องการคัดลอกฟิลด์ทั้งหมดยกเว้นแน่นอนว่าคีย์หลัก (id) นี่เป็นแบบสอบถามแบบช็อตเดียวที่จะไม่ใช้ในสคริปต์หรือรหัสใด ๆ

ฉันพบวิธีของฉันกับ PL / SQL แต่ฉันแน่ใจว่า SQL IDE อื่น ๆ จะทำอย่างไร ฉันทำพื้นฐาน

SELECT * 
FROM mytable 
WHERE id=42;

จากนั้นส่งออกไปยังไฟล์ SQL ที่ฉันสามารถหา

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

ฉันเพิ่งแก้ไขและใช้งาน:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);

0

ฉันมักจะใช้รูปแบบของสิ่งที่ mu โพสต์สั้นเกินไป:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

ตราบใดที่ตารางมีเขตข้อมูลที่เหมือนกัน (ยกเว้นการเพิ่มอัตโนมัติในตารางบันทึก) จากนั้นก็ใช้งานได้ดี

เนื่องจากฉันใช้โพรซีเดอร์ที่เก็บไว้เมื่อใดก็ตามที่เป็นไปได้ (เพื่อทำให้ชีวิตง่ายขึ้นสำหรับโปรแกรมเมอร์คนอื่น ๆ ที่ไม่คุ้นเคยกับฐานข้อมูล) สิ่งนี้แก้ปัญหาการกลับไปและอัปเดตโพรซีเดอร์ทุกครั้งที่คุณเพิ่มฟิลด์ใหม่ลงในตาราง

นอกจากนี้ยังช่วยให้มั่นใจว่าถ้าคุณเพิ่มเขตข้อมูลใหม่ลงในตารางพวกเขาจะเริ่มปรากฏในตารางบันทึกทันทีโดยไม่ต้องอัปเดตฐานข้อมูลแบบสอบถามของคุณ (เว้นแต่แน่นอนว่าคุณมีบางส่วนที่ตั้งค่าเขตข้อมูลไว้อย่างชัดเจน)

คำเตือน:คุณจะต้องแน่ใจว่าได้เพิ่มเขตข้อมูลใหม่ใด ๆ ลงในทั้งสองตารางในเวลาเดียวกันเพื่อให้คำสั่งฟิลด์ยังคงเหมือนเดิม ... มิฉะนั้นคุณจะเริ่มได้รับข้อผิดพลาดแปลก ๆ หากคุณเป็นคนเดียวที่เขียนอินเทอร์เฟซฐานข้อมูลและคุณก็ระวังให้ดี มิฉะนั้นให้ตั้งชื่อฟิลด์ทั้งหมดของคุณ

หมายเหตุ:ในความคิดที่สองเว้นแต่ว่าคุณกำลังทำงานในโครงการเดี่ยวที่คุณแน่ใจว่าจะไม่มีคนอื่นที่ทำงานในนั้นติดอยู่กับรายชื่อชื่อฟิลด์ทั้งหมดอย่างชัดเจนและอัปเดตคำสั่งบันทึกของคุณเมื่อสคีมาของคุณมีการเปลี่ยนแปลง ทางลัดนี้อาจไม่คุ้มค่ากับอาการปวดหัวในระยะยาวซึ่งอาจเป็นสาเหตุ ... โดยเฉพาะในระบบการผลิต


0
ใส่ลงใน "dbMyDataBase". "tblMyTable" 
(
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

เลือก 
    โมฆะ  
    `Column2`, 
    `Column3`, 
    'CustomValue' เป็นคอลัมน์ 4 
จาก "dbMyDataBase" .tblMyTable` 
WHERE `tblMyTable '.Column2` =' UniqueValueOfTheKey ' 
; 
/ * mySQL 5.6 * /

3
ลองเพิ่มคำอธิบายโดยละเอียดเพิ่มเติมหรือขยายคำตอบอื่น ๆ ออกไป
Azsgy

-1

ดัมพ์แถวที่คุณต้องการ sql จากนั้นใช้ SQL ที่สร้างขึ้นหักคอลัมน์ ID เพื่ออิมพอร์ตกลับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.