829

How do I copy or clone or duplicate the data, structure, and indices of a MySQL table to a new one?

This is what I've found so far.

This will copy the data and the structure, but not the indices:

create table {new_table} select * from {old_table};

This will copy the structure and indices, but not the data:

create table {new_table} like {old_table};
DwB
  • 37,124
  • 11
  • 56
  • 82
xkcd150
  • 8,767
  • 3
  • 23
  • 17
  • 4
    possible duplicate of [run mysql create table by select another and copied the indexes automatically](http://stackoverflow.com/questions/2415855/run-mysql-create-table-by-select-another-and-copied-the-indexes-automatically) – David Brossard May 31 '15 at 14:42
  • Also it won't copy your primary key, so you need to Alter Table and set it afterwards. – easleyfixed Apr 18 '23 at 21:45

15 Answers15

1815

To copy with indexes and triggers do these 2 queries:

CREATE TABLE new_table LIKE old_table; 
INSERT INTO new_table SELECT * FROM old_table;

To copy just structure and data use this one:

CREATE TABLE new_table AS SELECT * FROM old_table;

I've asked this before:

Copy a MySQL table including indexes

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Haim Evgi
  • 123,187
  • 45
  • 217
  • 223
  • 19
    Worth noting that foreign keys pointing to oldtable will need to be copied to newtable (if you're replacing oldtable) – George Oct 03 '16 at 13:01
  • 4
    Does this work for big tables (millions of records)?.. I am asking because I don't know how this `select *` will perform in huge tables. – fguillen Dec 01 '16 at 17:23
  • 8
    To give a rough idea, the insert operation took 27mins on a table of 16M rows (with 5 indexes) on a AWS db.r3.large instance – hello_harry Apr 19 '17 at 16:00
  • 7
    It is worth noting that while this recreates the indexes from the table being copied, it does _not_ carry over any foreign key constraints. – WebSmithery Aug 22 '17 at 05:53
  • 26
    Note: This won't copy the `AUTO_INCREMENT` value. – Matt Janssen Nov 02 '17 at 20:11
  • 2
    This technique did not work for me. It produced an error: `#1062 - Duplicate entry '1' for key 'ID'`, even though there was only one row containing the value 1 for ID. I had to intervene after the first step and remove the AUTO_INCREMENT UNIQUE index on that column before the rows would be allowed to be inserted. – Jason R. Coombs Nov 17 '17 at 17:04
  • 2
    I suspect if you wish to also copy the AUTO_INCREMENT and not run into the issue I encountered, you need to include these two statements after creation: `SELECT @ai := \`AUTO_INCREMENT\` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'yourdbname' AND TABLE_NAME = 'oldtable'; alter table newtable AUTO_INCREMENT=@ai; `. I've been unable to verify this technique as my account doesn't have privilege to update the auto_increment. – Jason R. Coombs Nov 17 '17 at 17:32
  • `CREATE TABLE newtable LIKE oldtable;` did not work for SQLite. Perhaps because `LIKE` doesn't work in this context in SQLite. Does anyone know how to duplicate a table (data and indexes) in SQLite? – puifais Nov 21 '17 at 00:11
  • 1
    If you want to copy a lot of rows lock the new table before the insert and unlock it after: indexes will be redone just once. – Natxet Feb 02 '18 at 18:46
  • I'd also add another statement to verify that they're indeed the same table using `CHECKSUM TABLE newtable, oldtable;`. This isn't _exactly_ foolproof, as are no checksum verifications. If the two Checksum columns are the same, the tables are _highly likely_ to be the same, if not they're _certainly_ not the same. – Nae May 14 '18 at 14:33
  • May want to include the IF NOT EXIST clause in the CREATE TABLE statement. (See: http://www.mysqltutorial.org/mysql-copy-table-data.aspx) – slaman Jun 01 '18 at 20:29
  • 1
    To copy just a fragment of the old_table to new use the LIMIT keyword – fokosun Dec 17 '18 at 19:24
  • From [mysql docs](https://dev.mysql.com/doc/refman/5.7/en/create-table-like.html): `If the original table is a TEMPORARY table, CREATE TABLE ... LIKE does not preserve TEMPORARY.` – sam-6174 Feb 27 '19 at 04:16
  • This technique did not work for me today, I suppose because the table had an AUTO_INCREMENT field *and* the database was part of a master-master replication relationship with the my.cnf settings on one side to use even increments and the other odd. Adding the following line before running the insert fixed it for me: SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'; – Curtis Jul 16 '19 at 15:23
  • Additional note to my above comment: Reading the docs would not make me think this would solve the issue I was having (missing records due to duplicate keys), but I discovered this is what phpMyAdmin runs when it copies a table, and I confirmed it preserves the auto-increment values from the original table. – Curtis Jul 16 '19 at 15:29
  • Perfect for "undo-ing" a query. –  Apr 15 '20 at 16:48
41

Apart from the solution above, you can use AS to make it in one line.

CREATE TABLE tbl_new AS SELECT * FROM tbl_old;
theDistantStar
  • 683
  • 5
  • 5
  • 42
    This will not copy indexes and triggers as the SELECT result is an (unnamed) temporary table and does not "carry" the metadata of the source table. Consider if you'd be using functions, it would make no sense. – chx Apr 30 '15 at 06:29
  • 2
    I was looking backup the structure table and move the data only, thus dropping indexes/constraints/etc. so I could recreate them. This answer was awesome in that regards seeing as Google sent me here. – Ellesedil Sep 28 '15 at 19:28
  • 4
    this is exactly what he already mentions in the question: **`create table {new_table} select * from {old_table};`** not an answer and provides no new information. – But those new buttons though.. Mar 07 '17 at 16:03
37

MySQL way:

CREATE TABLE recipes_new LIKE production.recipes;
INSERT recipes_new SELECT * FROM production.recipes;
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Krishneil
  • 1,432
  • 1
  • 18
  • 26
21

Go to phpMyAdmin and select your original table then select "Operations" tab in the "Copy table to (database.table)" area. Select the database where you want to copy and add a name for your new table.

copy table - phyMyAdmin Screenshot

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
spuvi86
  • 319
  • 2
  • 3
  • 1
    @AaronJSpetner This answer is still helpful for other users who come to this question and are able to utilize PHPMyAdmin to solve the problem. – reformed Oct 31 '18 at 15:01
4

I found the same situation and the approach which I took was as follows:

  1. Execute SHOW CREATE TABLE <table name to clone> : This will give you the Create Table syntax for the table which you want to clone
  2. Run the CREATE TABLE query by changing the table name to clone the table.

This will create exact replica of the table which you want to clone along with indexes. The only thing which you then need is to rename the indexes (if required).

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Jai
  • 41
  • 2
3

The better way to duplicate a table is using only DDL statement. In this way, independently from the number of records in the table, you can perform the duplication instantly.

My purpose is:

DROP TABLE IF EXISTS table_name_OLD;
CREATE TABLE table_name_NEW LIKE table_name;
RENAME TABLE table_name TO table_name_OLD;
RENAME TABLE table_name _NEW TO table_name;

This avoids the INSERT AS SELECT statement that, in case of table with a lot of records can take time to be executed.

I suggest also to create a PLSQL procedure as the following example:

DELIMITER //
CREATE PROCEDURE backup_table(tbl_name varchar(255))
BEGIN
  -- DROP TABLE IF EXISTS GLS_DEVICES_OLD;
  SET @query = concat('DROP TABLE IF EXISTS ',tbl_name,'_OLD');
  PREPARE stmt FROM @query;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

  -- CREATE TABLE GLS_DEVICES_NEW LIKE GLS_DEVICES;
  SET @query = concat('CREATE TABLE ',tbl_name,'_NEW LIKE ',tbl_name);
  PREPARE stmt FROM @query;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

  -- RENAME TABLE GLS_DEVICES TO GLS_DEVICES_OLD;
  SET @query = concat('RENAME TABLE ',tbl_name,' TO ',tbl_name,'_OLD');
  PREPARE stmt FROM @query;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;  

  --  RENAME TABLE GLS_DEVICES_NEW TO GLS_DEVICES;
  SET @query = concat('RENAME TABLE ',tbl_name,'_NEW TO ',tbl_name);
  PREPARE stmt FROM @query;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt; 
END//
DELIMITER ;

Have a nice day! Alex

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Alessandro
  • 129
  • 1
2

To duplicate a table and its structure without data from a different a database use this. On the new database sql type

CREATE TABLE currentdatabase.tablename LIKE olddatabase.tablename

Edd Michira
  • 101
  • 1
  • 3
2

Worths to mention the importance of checking if the table already exists before trying to duplicate it:

CREATE TABLE IF NOT EXISTS new_table LIKE old_table;

INSERT new_table
SELECT * FROM old_table;

As was said by the previous answers this will copy structure, data and all the dependent objects of the table.

See MySql Tutorial:

piertoni
  • 1,933
  • 1
  • 18
  • 30
2

Simple Cloning: it create a table from another table without taking into account any column attributes and indexes.

CREATE TABLE new_table SELECT * FROM original_table;

Shallow Cloning: This will only create an empty table base on the structure of the original table

CREATE TABLE new_table LIKE original_table;

The following command would create an empty table base on the original table.

CREATE TABLE adminUsers LIKE users;

Deep Cloning: This means the new table gets to have all the attributes of each column and indexes of the existing table. This quite useful if you want to maintain the indexes and attributes of the existing table.

CREATE TABLE new_table LIKE original_table;

INSERT INTO new_table SELECT * FROM original_table;

https://towardsdatascience.com/how-to-clone-tables-in-sql-dd29586ec89c

sparsh turkane
  • 1,165
  • 12
  • 13
2
// To copy specific column data use this one:
CREATE TABLE ut_axis_existrec LIKE ut_karvy_annexure; // To create new table

INSERT INTO ut_axis_existrec
(funding_ac,micr_no, warrant_no,
amount,invname,mfundcode,funding_dt,status,remarks1,amc_remark,created_at) 
SELECT  
t1.funding_ac,
t1.micr_no,
t1.warrant_no,
t1.amount,
t1.invname,
t1.mfund_code,
t1.funding_dt,
t1.status,
t1.remarks1,
t1.created_at
from ut_axis_karvy
inner join 
ut_axis_karvy_master as t2
on t1.micr_no = t2.micr_no;
Sonu Chohan
  • 141
  • 1
  • 5
1

After I tried the solution above, I come up with my own way.

My solution a little manual and needs DBMS.

First, export the data.

Second, open the export data.

Third, replace old table name with new table name.

Fourth, change all the trigger name in the data (I use MySQL and it show error when I don't change trigger name).

Fifth, import your edited SQL data to the database.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Võ Minh
  • 155
  • 2
  • 12
1

Expanding on this answer one could use a stored procedure:

CALL duplicate_table('tableName');

Which will result in a duplicate table called tableName_20181022235959 If called when

SELECT NOW();

results:

2018-10-22 23:59:59

Implementation

DELIMITER $$
CREATE PROCEDURE duplicate_table(IN tableName VARCHAR(255))
  BEGIN
    DECLARE schemaName VARCHAR(255) DEFAULT SCHEMA();
    DECLARE today VARCHAR(14) DEFAULT REPLACE(REPLACE(REPLACE(NOW(), '-', ''), ' ', ''), ':', ''); -- update @ year 10000
    DECLARE backupTableName VARCHAR(255) DEFAULT CONCAT(tableName, '_', today);

    IF fn_table_exists(schemaName, tableName)
      THEN
        CALL statement(CONCAT('CREATE TABLE IF NOT EXISTS ', backupTableName,' LIKE ', tableName));
        CALL statement(CONCAT('INSERT INTO ', backupTableName,' SELECT * FROM ', tableName));
        CALL statement(CONCAT('CHECKSUM TABLE ', backupTableName,', ', tableName));
      ELSE
        SELECT CONCAT('ERROR: Table "', tableName, '" does not exist in the schema "', schemaName, '".') AS ErrorMessage;
      END IF;
  END $$
DELIMITER ;

DELIMITER $$
CREATE FUNCTION fn_table_exists(schemaName VARCHAR(255), tableName VARCHAR(255))
  RETURNS TINYINT(1)
  BEGIN
    DECLARE totalTablesCount INT DEFAULT (
      SELECT COUNT(*)
      FROM information_schema.TABLES
      WHERE (TABLE_SCHEMA COLLATE utf8_general_ci = schemaName COLLATE utf8_general_ci)
        AND (TABLE_NAME COLLATE utf8_general_ci = tableName COLLATE utf8_general_ci)
    );
    RETURN IF(
      totalTablesCount > 0,
      TRUE,
      FALSE
    );
  END $$
DELIMITER ;

DELIMITER $$
CREATE PROCEDURE statement(IN dynamic_statement TEXT)
  BEGIN
      SET @dynamic_statement := dynamic_statement;
      PREPARE prepared_statement FROM @dynamic_statement;
      EXECUTE prepared_statement;
      DEALLOCATE PREPARE prepared_statement;
  END $$
DELIMITER ;
Nae
  • 14,209
  • 7
  • 52
  • 79
1

To create table structure only use this below code :

CREATE TABLE new_table LIKE current_table; 

To copy data from table to another use this below code :

INSERT INTO new_table SELECT * FROM current_table;
Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
0

Try this :

`CREATE TABLE new-table (id INT(11) auto_increment primary key) SELECT old-table.name, old-table.group, old-table.floor, old-table.age from old-table;`

I selected 4 columns from old-table and made a new table.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
Crazy_DT0
  • 1
  • 1
-2

FOR MySQL

CREATE TABLE newtable LIKE oldtable ; 
INSERT newtable SELECT * FROM oldtable ;

FOR MSSQL Use MyDatabase:

Select * into newCustomersTable  from oldCustomersTable;

This SQL is used for copying tables, here the contents of oldCustomersTable will be copied to newCustomersTable.
Make sure the newCustomersTable does not exist in the database.

Krishneil
  • 1,432
  • 1
  • 18
  • 26
  • 4
    Thows error SQL Error (3172): Undeclared variable: 'newCustomerTable' – mikewasmike May 30 '16 at 14:41
  • You must be doing something wrong. As this will work 100 %. Read before your give a negative vote. Content reference for you. http://www.w3schools.com/sql/sql_select_into.asp – Krishneil Dec 18 '16 at 20:16
  • 1
    Note that the question is about MySQL. Some SQL syntax may not be supported. – mikewasmike Dec 20 '16 at 05:41
  • 1
    MySQL Way CREATE TABLE recipes_new LIKE production.recipes; INSERT recipes_new SELECT * FROM production.recipes; – Krishneil Dec 20 '16 at 20:12
  • Your method is wrong. For mysql there is correct way. http://dev.mysql.com/doc/refman/5.7/en/ansi-diff-select-into-table.html – Daniel Jan 11 '17 at 21:40
  • 1
    I have edited my question as the previous answer was for only MSSQLL – Krishneil Nov 03 '17 at 01:20