Làm cách nào để sao chép một hàng và chèn vào cùng một bảng với trường tự động trong MySQL?


233

Trong MySQL, tôi đang cố gắng sao chép một hàng với tính năng tự động column ID=1chèn dữ liệu vào cùng một bảng với một hàng mới column ID=2.

Làm thế nào tôi có thể làm điều này trong một truy vấn duy nhất?

Câu trả lời:


351

Sử dụng INSERT ... SELECT:

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

nơi c1, c2, ...là tất cả các cột trừ id. Nếu bạn muốn chèn một cách rõ ràng bằng một idtrong 2 thì hãy đưa nó vào danh sách cột INSERT và CHỌN của bạn:

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

Tất nhiên, bạn sẽ phải chăm sóc một bản sao có thể có idcủa 2 trong trường hợp thứ hai.


1
Bạn có thể lập trình lấy tên của các cột bằng cách sử dụng Information_SCHema theo cách lập trình ... Tôi tự hỏi liệu bạn có thể làm điều đó như một truy vấn phụ và một số hàm chuỗi không? Hmmm ...
Yzmir Ramirez

1
@Yzmir: Cuối cùng, bạn sẽ phải sử dụng SQL động và điều đó thường sẽ yêu cầu xây dựng một thủ tục được lưu trữ. Có vẻ như rắc rối hơn giá trị của nó khi bạn nên có một danh sách các tên cột tiện dụng.
mu quá ngắn

6
Đồng ý ... từ kinh nghiệm của tôi khi bạn thực hiện Quy trình được lưu trữ mà bạn không quay lại - bạn đã kết hôn với cơ sở dữ liệu đó ngay bây giờ và chỉ cần thêm chi phí bất cứ khi nào bạn muốn thay đổi.
Yzmir Ramirez

11
@YzmirRamirez, bạn làm cho nó có vẻ như hôn nhân vốn dĩ là một điều xấu. :)
Giáo sư Falken

1
Làm cách nào để thêm một giá trị tùy chỉnh trong cột với tất cả các trường được sao chép khác?
Manish Kumar

49

IMO, tốt nhất dường như chỉ sử dụng các câu lệnh sql để sao chép hàng đó, đồng thời chỉ tham chiếu các cột bạn phải và muốn thay đổi.

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;

Xem thêm av8n.com - Cách sao chép bản ghi SQL

Những lợi ích:

  • Các câu lệnh SQL 2 chỉ đề cập đến các trường cần được thay đổi trong quá trình nhân bản. Họ không biết về - hoặc quan tâm đến - các lĩnh vực khác. Các lĩnh vực khác chỉ cần đi cùng cho đi, không thay đổi. Điều này làm cho các câu lệnh SQL dễ viết hơn, dễ đọc hơn, dễ bảo trì hơn và dễ mở rộng hơn.
  • Chỉ các câu lệnh MySQL thông thường được sử dụng. Không có công cụ hoặc ngôn ngữ lập trình khác được yêu cầu.
  • Một bản ghi hoàn toàn chính xác được chèn vào your_tabletrong một hoạt động nguyên tử.

3
Nó có đường nối, rằng thủ thuật hay này (tôi thích nó, nhưng nó không hiệu quả với tôi) không hoạt động trên các bảng có chứa các cột TEXT / VARCHAR. Tôi đã thử và nhận được: (1163): Loại bảng được sử dụng không hỗ trợ các cột BLOB / TEXT. Điều đó tất nhiên hạn chế việc sử dụng trên MySQL rất nhiều! Có thể, trong tương lai, các giới hạn này được dỡ bỏ hoặc trên các hệ thống db khác, nó hoạt động được, nhưng hiện tại nó thực sự bị giới hạn.
Juergen

Tôi thực sự thích việc sử dụng thông minh của bảng tạm thời. Vì vậy, hữu ích cho các bảng với một tấn cột!
Lasma

1
Có vẻ tốt, nhưng khi tôi chạy truy vấn đầu tiên trong MySQL, tôi nhận được Error Code: 1113. A table must have at least 1 column.
vật lý

3
Câu trả lời tốt nhất cho rất nhiều cột. Nhưng SET id=NULLcó thể gây ra lỗi Column 'id' cannot be null. Nên được thay thế bằngUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder

1
@physicalWOR bạn cần đảm bảo hai dòng đầu tiên là một câu lệnh.
Samuurai

16

Nói cái bàn là thế user(id, user_name, user_email).

Bạn có thể sử dụng truy vấn này:

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

29
Bạn phải luôn chỉ định tên cột khi sử dụng INSERT, nếu không bạn sẽ gặp các lỗi lạ và thú vị khi lược đồ của bạn thay đổi.
mu quá ngắn

2
Thật kỳ lạ và thú vị. : D
sparkyShorts

Không hoạt động với sqlite. Result: near "SELECT": syntax error
kyb

10

Điều này đã giúp và nó hỗ trợ một cột 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;

Bằng cách nào thì điều này tốt hơn những câu trả lời khác ở đây?
Smar

3
Tôi nghĩ nó khá tốt nếu bạn có một bảng với 100 trường. Ngoại trừ có thể có một ràng buộc không null đối với id khiến nó thất bại
Loïc Faure-Lacroix

Mã lỗi: 1136. Đếm cột không khớp với giá trị đếm ở hàng 1
Oleksii Kyslytsyn 30/03/2017

Điều này tốt hơn nhiều nếu bạn có một bảng với 100 cột.
Tyler S. Loeper

Đây không phải là những gì parvus đã nói, những năm trước đó sao?
ToolmakerSteve

7

Để có giải pháp nhanh chóng, gọn gàng không yêu cầu bạn đặt tên cột, bạn có thể sử dụng câu lệnh được chuẩn bị như mô tả tại đây: https://stackoverflow.com/a/23944285/292677

Nếu bạn cần một giải pháp phức tạp để bạn có thể làm điều này thường xuyên, bạn có thể sử dụng quy trình này:

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

Bạn có thể chạy nó với:

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

Ví dụ

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

TUYÊN BỐ TỪ CHỐI: Giải pháp này chỉ dành cho người thường xuyên lặp lại các hàng trong nhiều bảng. Nó có thể nguy hiểm trong tay của một người dùng lừa đảo.


3

Bạn cũng có thể chuyển vào '0' làm giá trị cho cột để tự động tăng, giá trị đúng sẽ được sử dụng khi bản ghi được tạo. Điều này là rất dễ dàng hơn nhiều so với các bảng tạm thời.

Nguồn: Sao chép các hàng trong MySQL (xem bình luận thứ hai, của TRiG, ​​cho giải pháp đầu tiên, bởi Lore)


1
Phương pháp này hoạt động với các phiên bản MySQL mới hơn khi NULL không được chấp nhận.
err

3

Rất nhiều câu trả lời tuyệt vời ở đây. Dưới đây là một mẫu về quy trình được lưu trữ mà tôi đã viết để hoàn thành nhiệm vụ này cho Ứng dụng web mà tôi đang phát triển:

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

trong phiên bản hiện tại của cài đặt MariaDB / MySQL id = null cho # 1048 - Cột 'id' không thể rỗng, cài đặt id = 0 hoạt động;
Shelbypereira

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

3
Làm thế nào là điều này tốt hơn so với các câu trả lời khác ở đây?
Smar

1
@smar imo nó dễ hiểu hơn
Satbir Kira

2

Nếu bạn có thể sử dụng MySQL Workbench, bạn có thể thực hiện việc này bằng cách nhấp chuột phải vào hàng và chọn 'Sao chép hàng', sau đó bấm chuột phải vào hàng trống và chọn 'Dán hàng', sau đó thay đổi ID, sau đó thay đổi ID nhấp vào 'Áp dụng'.

Sao chép hàng:

nhập mô tả hình ảnh ở đây

Dán hàng đã sao chép vào hàng trống:

nhập mô tả hình ảnh ở đây

Thay đổi ID:

nhập mô tả hình ảnh ở đây

Ứng dụng:

nhập mô tả hình ảnh ở đây


0

Tôi đã tìm kiếm tính năng tương tự nhưng tôi không sử dụng MySQL. Tôi muốn sao chép TẤT CẢ các trường trừ khóa chính (id). Đây là truy vấn một lần, không được sử dụng trong bất kỳ tập lệnh hoặc mã nào.

Tôi đã tìm thấy cách của mình với PL / SQL nhưng tôi chắc chắn rằng bất kỳ IDE SQL nào khác sẽ làm được. Tôi đã làm một cơ bản

SELECT * 
FROM mytable 
WHERE id=42;

Sau đó xuất nó thành tệp SQL nơi tôi có thể tìm thấy

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

Tôi chỉ chỉnh sửa nó và sử dụng nó:

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

0

Tôi có xu hướng sử dụng một biến thể của những gì mu quá ngắn được đăng:

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

Miễn là các bảng có các trường giống hệt nhau (ngoại trừ tăng tự động trên bảng nhật ký), thì bảng này hoạt động độc đáo.

Vì tôi sử dụng các thủ tục được lưu trữ bất cứ khi nào có thể (để làm cho cuộc sống dễ dàng hơn đối với các lập trình viên khác, những người không quá quen thuộc với cơ sở dữ liệu), điều này giải quyết vấn đề phải quay lại và cập nhật các thủ tục mỗi khi bạn thêm trường mới vào bảng.

Nó cũng đảm bảo rằng nếu bạn thêm các trường mới vào một bảng, chúng sẽ bắt đầu xuất hiện trong bảng nhật ký ngay lập tức mà không phải cập nhật các truy vấn cơ sở dữ liệu của bạn (trừ khi tất nhiên bạn có một số trường đặt trường rõ ràng)

Cảnh báo: Bạn sẽ muốn đảm bảo thêm bất kỳ trường mới nào vào cả hai bảng cùng một lúc để thứ tự trường giữ nguyên ... nếu không bạn sẽ bắt đầu gặp lỗi lạ. Nếu bạn là người duy nhất viết giao diện cơ sở dữ liệu VÀ bạn rất cẩn thận thì điều này sẽ hoạt động tốt. Nếu không, hãy đặt tên cho tất cả các lĩnh vực của bạn.

Lưu ý: Về ý nghĩ thứ hai, trừ khi bạn đang làm việc trong một dự án solo mà bạn chắc chắn sẽ không có người khác làm việc trên đó để liệt kê rõ ràng tất cả các tên trường và cập nhật báo cáo nhật ký của bạn khi thay đổi lược đồ của bạn. Phím tắt này có lẽ không đáng để đau đầu lâu dài mà nó có thể gây ra ... đặc biệt là trên một hệ thống sản xuất.


0
XÁC NHẬN VÀO `dbMyDataBase`.`tblMyTable` 
(
    `IdAutoincrement`, 
    `Cột2`, 
    `Cột3`, 
    `Cột4` 
) 

LỰA CHỌN 
    VÔ GIÁ TRỊ,  
    `Cột2`, 
    `Cột3`, 
    'CustomValue' AS Cột4 
TỪ `dbMyDataBase`.`tblMyTable` 
Ở đâu `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/ * myQuery 5.6 * /

3
Hãy thử thêm một số giải thích chi tiết hơn hoặc làm thế nào điều này mở rộng cho các câu trả lời khác
Azsgy

-1

Kết xuất hàng bạn muốn sql và sau đó sử dụng SQL được tạo, trừ cột ID để nhập lại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.