mysql: Copy table structure including foreign keys - mysql

I know how to copy a table using create new_table like old_table, but that does not copy over the foreign key constraints as well. I can also do string manipulation on the result from show create table old_table (using regular expressions to replace the table name and the foreign key constraint names), but that seems error prone. Is there a better way to copy the structure of a table, including the foreign keys?

Possibly you could write a procedure that after the create table like prepares ALTER TABLE ... statements, based on information from:
SELECT *
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME LIKE '<table_name>'
AND TABLE_SCHEMA = '<db_name>'
AND REFERENCED_TABLE_NAME IS NOT NULL;

If a little side-scripting is OK, you can take advantage of SHOW CREATE TABLE in a few lines like so (PHP but concept works in any language):
// Get the create statement
$retrieve = "SHOW CREATE TABLE <yourtable>";
$create = <run the $retrieve statement>
// Isolate the "Create Table" index
$create = $create['Create Table'];
// Replace old table name with new table name everywhere
$create = preg_replace("/".$newname."/", $oldname, $create);
// You may need to rename foreign keys to prevent name re-use error.
// See http://stackoverflow.com/questions/12623651/
$create = preg_replace("/FK_/", "FK_TEMP_", $create);
// Create the new table
<run the $create statement>
Not very elegant, but it works so far. I'm doing this in a testing environment so I put this in my setUp() method.

Wrikken's answer inspired me. Let me extend it.
Well, things are more complicated. See: http://dev.mysql.com/doc/refman/5.1/en/create-table.html. It says, that there are going to be problems also with TEMPORARY tables and other things. The solution mentioned by Wrikken is a good approach, however, you will need at least one more lookup to get information about UPDATE and DELETE rules:
SELECT *
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
WHERE TABLE_NAME LIKE '<table_name>'
AND CONSTRAINT_SCHEMA = '<db_name>';
So, it might be a good idea to get a tool that simplifies the task. I personally use Adminer (https://sourceforge.net/projects/adminer/). It comes with an option to export whole DB (with all tables, triggers, foreign keys, ...). Once you export it (in SQL syntax) you can change DB name easily and import it back. I wrote about that at the bugs section of the project (see ticket 380).
Maybe you already have your favorite DB manager and do not want another one. You could follow these steps then:
Dump the DB using mysqldump -> you get file.sql
Create a new DB
Execute file.sql in the new DB
Both Adminer and mysqldump have an option to select only specific tables so you do not have to export whole DB. Should you need only the structure, not the data, use an option -d for mysqldump or click it in Adminer.

If you have phpMyAdmin, you can export only structure of your table, then change old table names to new in your .sql file and import it back.
It's rather quick way

If you just want to clean your table, you could copy all relevant data to your copy table. Than truncate and copy back. Result is, that you have your FK preserved.
CREATE TABLE IF NOT EXISTS t_copy LIKE t_origin;
INSERT INTO t_copy
SELECT t_origin.*
FROM t_origin;
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE t_origin;
INSERT INTO t_origin
SELECT t_copy.*
FROM t_copy;
DROP TABLE t_copy;
SET FOREIGN_KEY_CHECKS = 1;

I created a bash script to copy a table into another database, modifying the keys and constraints by adding a '_1' to them:
mysqldump -h ${host_ip} -u root -p${some_password} ${some_database} ${some_table} > some_filename
sed -i -r -e 's#KEY `([a-zA-Z0-9_]*)`#KEY `\1_1`#g' -e 's#CONSTRAINT `([a-zA-Z0-9_]*)`#CONSTRAINT `\1_1`#g' some_filename
mysql -h ${host_ip} -u root -p${some_password} ${some_new_database} < some_filename
This works to new database instances as well, but the 'sed' command won't be necessary. It's only necessary when source and destination databases are in the same instance.

Related

Insert only selected columns from MySQL dump file into database

I am having a simple (I think) problem.
I am having a dump of MySQL database before disaster.
I need to import and replace from this dump only three columns from single table (in over 5000 rows, so that's why I am aware of doing it manually).
What should I do to do it and do not destroy anything else in working database?
I am just thinking that there is an option to skip columns during import and replace (UPDATE command I think) only these I need.
I will be thankful for help :(
------------ UPDATE ---------------
Okay, I used PHPMyAdmin and first I used SELECT query to get only three columns from whole table. Then I dumped it and I have SQL file with a dump containing only three columns.
Now, having this dump, can I (I do not know how to name it) edit or change something inside this typical MySQL dump file to make it possible to import these three columns with replace all the existing values?
I mean - to make existing column empty, then use maybe "INSERT INTO" but to whole table?
It is just over 2600 rows and I can not change it manually, so it would be better do use automation.
As far as I know, this is not possible. You can try to use sed in order to extract only the table you want - but specifically 3 columns would be complicated if not impossible.
Can I restore a single table from a full mysql mysqldump file?
The best way would be as #Ali said and just import it to a temp DB and then export the required data/columns to a new dump.
Restore DB to temp db then:
mysql> CREATE TABLE `tempTable` AS SELECT `columnYouWant` from `table`;
$> mysqldump yourDB tempTable > temp.sql
// Since you updated the question:
You want to probably use REPLACE INTO with your dump with the --replace option - though this will delete the row and replace it, not just the individual columns. If you want just the individual columns, the only way I can think of is with UDPATE. To use UPDATE, your options are:
Multi-table update
UPDATE mydb.mytable AS dest JOIN tempdb.mytable AS origin USING (prim_key)
SET dest.col1 = origin.col1,
dest.col2 = origin.col2,
...
Then drop the temp database.
Search/Replace Dump
Take your dump and use the INSERT ... ON DUPLICATE KEY UPDATE option to add it to the end of each insert line (assuming you exported/dumped individual insert commands).

Any way to get all fillable fields by simple SQL query for Laravel Model?

Laravel model contain two value,
protected $table = 'table_name';
protected $fillable = [
'field_name1',
'field_name2'
];
When there are many fields in a table. It's need more time to copy one by one from table and paste. Is there any shortcut way to get all fields name including " (quotation) by SQL query.
No, there is no such command. You should use mysqldump tool to do so.
Please also note that
CREATE TABLE table1 as SELECT * FROM table2;
It will create table with the same architecture, but without indexes, better to use:
CREATE TABLE table1 like table2;
INSERT INTO table1 SELECT * FROM table2;
For getting all tables you can use:
show tables
You may also need to copy views, trigers, events, functions
MySQL Query :
SELECT CONCAT('"',COLUMN_NAME,'",') as fillable
FROM information_schema.columns
WHERE table_name = 'my_table';
I am not sure of your use case, but I would recommend mysqldump
With this you can dump your database into one SQL file and then reload it into the new database with:
mysqldump -u root -p password databaseName > /path/databaseName.sql
mysql -u root -p password newDatabaseName < /path/databaseName.sql
However, this requires that you use the command line, and have the new database created already.
Note: Using login credentials in the command line is not recommended.

What is a good way to erase the entire data and load the new data in a service table?

I am new in MySQL.
I receive full metadata every day.
However, I do not know which data is added, deleted and updated.
I use MySQL and the size of the data is about one million.
What is a good way to erase the entire data and load the new data in a service table?
I think about the following methods.
first option,
Run Delete and insert in a transaction.
second option,
RENAME TABLE foo TO foo_old, foo_new To foo
Please advise me how to deal with it.
you can truncate the table and import your new data afterwards. You dont need to rename anything.
query truncate:
TRUNCATE TABLE {tableName};
cli import:
mysql -u {username} -p {database} < {importFile.sql}
The answer by #Ben is perfect if you have data outside MySQL in a file. If your data is in another table then try this:
# Truncate table
truncate table table_name;
# Inserting data to new table, Provided, same column names in succession
insert into target_table_name select * from old_table_name;
(or)
insert into target_table_name (column names) select column_names from old_table_name;

How do I add rows from a table of a MySQL database A to an existing table in database B

I'm using MySQL.
I have a "customers" table in database A (located on server).
I want to add them to the customer table in database B (located on localhost) without deleting anything.
I'm very new to SQL commands or MySQL in general so try to be the most explanatory as you can.
If you need more information about something I will edit the post and add it.
(I have MySQL workbench)
Thanks.
On server (DB A):
# Sets our database as default, so we wont have to write `database`.`table` in the consecutive queries.
# Replace *database* with your database name.
USE *database*;
# Makes a copy of the customers table - named customers_export.
# This copy contains all the fields and rows from the original table (without indexes),
# and if you want, you can add a WHERE clause to filter out some data
CREATE TABLE `customers_export` SELECT * FROM `customers`;
Since you are using mysql_workbench, Do a Data Export (in MANAGEMENT section) by choosing the relevant database and only the customers_export table.
On localhost (DB B):
Assuming the database name is the same (otherwise you will need to change the database name in the dump file), do a Data Import/Restore by selecting the dump file which we exported in the previous step.
This will create the customer_export table.
# Set as default
USE *database*;
# If the data you want to import contains *NO* collisions (same primary or unique values in both tables), the structure and table name is the same
INSERT INTO `customers` SELECT * FROM `customers_export`;
And we are done.
If it does have collisions, or you want to play change the column names, some values and etc - you will need to either modify the select statement or update the customers_export table to suit your needs.
Also, back up the customers table on the second server - in case something goes wrong with the insert.
Finally - drop the customers_export table on both servers.
Just use this on localhost:
mysqldump -u YOUR_DATABASE_USER -p YOUR_DATABASE_PASS -h YOUR_SERVER_IP databaseA customers > customer.sql
mysql -u YOUR_DATABASE_USER -p YOUR_DATABASE_PASS databaseB < customer.sql
PD: If want some explanation just tell me

Truncate all tables (most of which have constraints). How to temporarily drop them

I have a development database (MYSQL) which I would like to load with fresh data at some point. I would like to delete the content of all tables.
What is the best way, as automated as possible, to delete the content of all tables (including those that have foreign key constraints). Is there a truncate all/ drop all equivalent constraints?
Thanks
I think you can do the following:
Disable the foreign key constraint check
mysql> SET FOREIGN_KEY_CHECKS = 0;
Truncate your tables
mysql> TRUNCATE MY_TABLE;
Enable the foreign key constraint check
mysql> SET FOREIGN_KEY_CHECKS = 1;
I prefer disabling the foreign key constraints temporarily to dropping/recreating them.
If you want truncate REALLY all tables better way i'm think drop and create database with previously extracted database schema. Or you just can two copy of same database - test and empty. After filling your tables, just delete test db and copy empty to test.
TRUNCATE (TABLE) tbl_name will truncate a single table. You can stick that in a script and loop through it with all of your table names.
http://dev.mysql.com/doc/refman/5.0/en/truncate.html
You may want to look into migrations, too, but I think Alexey has the right approach there. It's very similar to how RoR handles rebuilding the test database on each run.
Here's what I do from the command prompt:
mysql -Nse 'show tables' DATABASE_NAME | while read table; do mysql -e "SET FOREIGN_KEY_CHECKS = 0; TRUNCATE table $table" DATABASE_NAME; done
Problem is, if you require authentication, you will need to add a -u YOUR_USERNAME -pYOURPASSWORD after both mysql commands.
If you don't want to enter your password at the command prompt (I don't ever), then you'll need to copy and paste the password after every prompt, which may be several times depending on the number of tables.