How do I quickly rename a MySQL database (change its schema name)?
Usually I just dump a database and re-import it with a new name. This is not an option for very big databases. Apparently RENAME {DATABASE | SCHEMA} db_name TO new_db_name; does bad things, exists only in a handful of versions, and is a bad idea overall.
This needs to work with InnoDB, which stores things very differently than MyISAM.
For InnoDB, the following seems to work: create the new empty database, then rename each table in turn into the new database:
RENAME TABLE old_db.table TO new_db.table;
You will need to adjust the permissions after that.
For scripting in a shell, you can use either of the following:
mysql -u username -ppassword old_db -sNe 'show tables' | while read table; \
do mysql -u username -ppassword -sNe "rename table old_db.$table to new_db.$table"; done
OR
for table in `mysql -u root -ppassword -s -N -e "use old_db;show tables from old_db;"`; do mysql -u root -ppassword -s -N -e "use old_db;rename table old_db.$table to new_db.$table;"; done;
Notes:
There is no space between the option -p and the password. If your database has no password, remove the -u username -ppassword part.
If some table has a trigger, it cannot be moved to another database using above method (will result Trigger in wrong schema error). If that is the case, use a traditional way to clone a database and then drop the old one:
mysqldump old_db | mysql new_db
If you have stored procedures, you can copy them afterwards:
mysqldump -R old_db | mysql new_db
Use these few simple commands:
mysqldump -u username -p -v olddatabase > olddbdump.sql
mysqladmin -u username -p create newdatabase
mysql -u username -p newdatabase < olddbdump.sql
Or to reduce I/O use the following as suggested by #Pablo Marin-Garcia:
mysqladmin -u username -p create newdatabase
mysqldump -u username -v olddatabase -p | mysql -u username -p -D newdatabase
I think the solution is simpler and was suggested by some developers. phpMyAdmin has an operation for this.
From phpMyAdmin, select the database you want to select. In the tabs there's one called Operations, go to the rename section. That's all.
It does, as many suggested, create a new database with the new name, dump all tables of the old database into the new database and drop the old database.
You can use SQL to generate an SQL script to transfer each table in your source database to the destination database.
You must create the destination database before running the script generated from the command.
You can use either of these two scripts (I originally suggested the former and someone "improved" my answer to use GROUP_CONCAT. Take your pick, but I prefer the original):
SELECT CONCAT('RENAME TABLE $1.', table_name, ' TO $2.', table_name, '; ')
FROM information_schema.TABLES
WHERE table_schema='$1';
or
SELECT GROUP_CONCAT('RENAME TABLE $1.', table_name, ' TO $2.', table_name SEPARATOR '; ')
FROM information_schema.TABLES
WHERE table_schema='$1';
($1 and $2 are source and target respectively)
This will generate a SQL command that you'll have to then run.
Note that GROUP_CONCAT has a default length limit that may be exceeded for databases with a large number of tables. You can alter that limit by running SET SESSION group_concat_max_len = 100000000; (or some other large number).
Emulating the missing RENAME DATABASE command in MySQL:
Create a new database
Create the rename queries with:
SELECT CONCAT('RENAME TABLE ',table_schema,'.`',table_name,
'` TO ','new_schema.`',table_name,'`;')
FROM information_schema.TABLES
WHERE table_schema LIKE 'old_schema';
Run that output
Delete old database
It was taken from Emulating The Missing RENAME DATABASE Command in MySQL.
You may use this shell script:
Reference: How to rename a MySQL database?
#!/bin/bash
set -e # terminate execution on command failure
mysqlconn="mysql -u root -proot"
olddb=$1
newdb=$2
$mysqlconn -e "CREATE DATABASE $newdb"
params=$($mysqlconn -N -e "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES \
WHERE table_schema='$olddb'")
for name in $params; do
$mysqlconn -e "RENAME TABLE $olddb.$name to $newdb.$name";
done;
$mysqlconn -e "DROP DATABASE $olddb"
It's working:
$ sh rename_database.sh oldname newname
Three options:
Create the new database, bring down the server, move the files from one database folder to the other, and restart the server. Note that this will only work if ALL of your tables are MyISAM.
Create the new database, use CREATE TABLE ... LIKE statements, and then use INSERT ... SELECT * FROM statements.
Use mysqldump and reload with that file.
The simple way
Change to the database directory:
cd /var/lib/mysql/
Shut down MySQL... This is important!
/etc/init.d/mysql stop
Okay, this way doesn't work for InnoDB or BDB-Databases.
Rename database:
mv old-name new-name
...or the table...
cd database/
mv old-name.frm new-name.frm
mv old-name.MYD new-name.MYD
mv old-name.MYI new-name.MYI
Restart MySQL
/etc/init.d/mysql start
Done...
OK, this way doesn't work with InnoDB or BDB databases. In this case you have to dump the database and re-import it.
Simplest bullet-and-fool-proof way of doing a complete rename (including dropping the old database at the end so it's a rename rather than a copy):
mysqladmin -uroot -pmypassword create newdbname
mysqldump -uroot -pmypassword --routines olddbname | mysql -uroot -pmypassword newdbname
mysqladmin -uroot -pmypassword drop olddbname
Steps:
Copy the lines into Notepad.
Replace all references to "olddbname", "newdbname", "mypassword" (+ optionally "root") with your equivalents.
Execute one by one on the command line (entering "y" when prompted).
I've only recently came across a very nice way to do it, works with MyISAM and InnoDB and is very fast:
RENAME TABLE old_db.table TO new_db.table;
I don't remember where I read it but credit goes to someone else not me.
This is what I use:
$ mysqldump -u root -p olddb >~/olddb.sql
$ mysql -u root -p
mysql> create database newdb;
mysql> use newdb
mysql> source ~/olddb.sql
mysql> drop database olddb;
MySQL does not support the renaming of a database through its command interface at the moment, but you can rename the database if you have access to the directory in which MySQL stores its databases. For default MySQL installations this is usually in the Data directory under the directory where MySQL was installed. Locate the name of the database you want to rename under the Data directory and rename it. Renaming the directory could cause some permissions issues though. Be aware.
Note: You must stop MySQL before you can rename the database
I would recommend creating a new database (using the name you want) and export/import the data you need from the old to the new. Pretty simple.
Well there are 2 methods:
Method 1: A well-known method for renaming database schema is by dumping the schema using Mysqldump and restoring it in another schema, and then dropping the old schema (if needed).
From Shell
mysqldump emp > emp.out
mysql -e "CREATE DATABASE employees;"
mysql employees < emp.out
mysql -e "DROP DATABASE emp;"
Although the above method is easy, it is time and space consuming. What if the schema is more than a 100GB? There are methods where you can pipe the above commands together to save on space, however it will not save time.
To remedy such situations, there is another quick method to rename schemas, however, some care must be taken while doing it.
Method 2: MySQL has a very good feature for renaming tables that even works across different schemas. This rename operation is atomic and no one else can access the table while its being renamed. This takes a short time to complete since changing a table’s name or its schema is only a metadata change. Here is procedural approach at doing the rename:
Create the new database schema with the desired name.
Rename the tables from old schema to new schema, using MySQL’s “RENAME TABLE” command.
Drop the old database schema.
If there are views, triggers, functions, stored procedures in the schema, those will need to be recreated too. MySQL’s “RENAME TABLE” fails if there are triggers exists on the tables. To remedy this we can do the following things :
1) Dump the triggers, events and stored routines in a separate file. This done using -E, -R flags (in addition to -t -d which dumps the triggers) to the mysqldump command. Once triggers are dumped, we will need to drop them from the schema, for RENAME TABLE command to work.
$ mysqldump <old_schema_name> -d -t -R -E > stored_routines_triggers_events.out
2) Generate a list of only “BASE” tables. These can be found using a query on information_schema.TABLES table.
mysql> select TABLE_NAME from information_schema.tables where
table_schema='<old_schema_name>' and TABLE_TYPE='BASE TABLE';
3) Dump the views in an out file. Views can be found using a query on the same information_schema.TABLES table.
mysql> select TABLE_NAME from information_schema.tables where
table_schema='<old_schema_name>' and TABLE_TYPE='VIEW';
$ mysqldump <database> <view1> <view2> … > views.out
4) Drop the triggers on the current tables in the old_schema.
mysql> DROP TRIGGER <trigger_name>;
...
5) Restore the above dump files once all the “Base” tables found in step #2 are renamed.
mysql> RENAME TABLE <old_schema>.table_name TO <new_schema>.table_name;
...
$ mysql <new_schema> < views.out
$ mysql <new_schema> < stored_routines_triggers_events.out
Intricacies with above methods : We may need to update the GRANTS for users such that they match the correct schema_name. These could fixed with a simple UPDATE on mysql.columns_priv, mysql.procs_priv, mysql.tables_priv, mysql.db tables updating the old_schema name to new_schema and calling “Flush privileges;”. Although “method 2″ seems a bit more complicated than the “method 1″, this is totally scriptable. A simple bash script to carry out the above steps in proper sequence, can help you save space and time while renaming database schemas next time.
The Percona Remote DBA team have written a script called “rename_db” that works in the following way :
[root#dba~]# /tmp/rename_db
rename_db <server> <database> <new_database>
To demonstrate the use of this script, used a sample schema “emp”, created test triggers, stored routines on that schema. Will try to rename the database schema using the script, which takes some seconds to complete as opposed to time consuming dump/restore method.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| emp |
| mysql |
| performance_schema |
| test |
+--------------------+
[root#dba ~]# time /tmp/rename_db localhost emp emp_test
create database emp_test DEFAULT CHARACTER SET latin1
drop trigger salary_trigger
rename table emp.__emp_new to emp_test.__emp_new
rename table emp._emp_new to emp_test._emp_new
rename table emp.departments to emp_test.departments
rename table emp.dept to emp_test.dept
rename table emp.dept_emp to emp_test.dept_emp
rename table emp.dept_manager to emp_test.dept_manager
rename table emp.emp to emp_test.emp
rename table emp.employees to emp_test.employees
rename table emp.salaries_temp to emp_test.salaries_temp
rename table emp.titles to emp_test.titles
loading views
loading triggers, routines and events
Dropping database emp
real 0m0.643s
user 0m0.053s
sys 0m0.131s
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| emp_test |
| mysql |
| performance_schema |
| test |
+--------------------+
As you can see in the above output the database schema “emp” was renamed to “emp_test” in less than a second. Lastly, This is the script from Percona that is used above for “method 2″.
#!/bin/bash
# Copyright 2013 Percona LLC and/or its affiliates
set -e
if [ -z "$3" ]; then
echo "rename_db <server> <database> <new_database>"
exit 1
fi
db_exists=`mysql -h $1 -e "show databases like '$3'" -sss`
if [ -n "$db_exists" ]; then
echo "ERROR: New database already exists $3"
exit 1
fi
TIMESTAMP=`date +%s`
character_set=`mysql -h $1 -e "show create database $2\G" -sss | grep ^Create | awk -F'CHARACTER SET ' '{print $2}' | awk '{print $1}'`
TABLES=`mysql -h $1 -e "select TABLE_NAME from information_schema.tables where table_schema='$2' and TABLE_TYPE='BASE TABLE'" -sss`
STATUS=$?
if [ "$STATUS" != 0 ] || [ -z "$TABLES" ]; then
echo "Error retrieving tables from $2"
exit 1
fi
echo "create database $3 DEFAULT CHARACTER SET $character_set"
mysql -h $1 -e "create database $3 DEFAULT CHARACTER SET $character_set"
TRIGGERS=`mysql -h $1 $2 -e "show triggers\G" | grep Trigger: | awk '{print $2}'`
VIEWS=`mysql -h $1 -e "select TABLE_NAME from information_schema.tables where table_schema='$2' and TABLE_TYPE='VIEW'" -sss`
if [ -n "$VIEWS" ]; then
mysqldump -h $1 $2 $VIEWS > /tmp/${2}_views${TIMESTAMP}.dump
fi
mysqldump -h $1 $2 -d -t -R -E > /tmp/${2}_triggers${TIMESTAMP}.dump
for TRIGGER in $TRIGGERS; do
echo "drop trigger $TRIGGER"
mysql -h $1 $2 -e "drop trigger $TRIGGER"
done
for TABLE in $TABLES; do
echo "rename table $2.$TABLE to $3.$TABLE"
mysql -h $1 $2 -e "SET FOREIGN_KEY_CHECKS=0; rename table $2.$TABLE to $3.$TABLE"
done
if [ -n "$VIEWS" ]; then
echo "loading views"
mysql -h $1 $3 < /tmp/${2}_views${TIMESTAMP}.dump
fi
echo "loading triggers, routines and events"
mysql -h $1 $3 < /tmp/${2}_triggers${TIMESTAMP}.dump
TABLES=`mysql -h $1 -e "select TABLE_NAME from information_schema.tables where table_schema='$2' and TABLE_TYPE='BASE TABLE'" -sss`
if [ -z "$TABLES" ]; then
echo "Dropping database $2"
mysql -h $1 $2 -e "drop database $2"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.columns_priv where db='$2'" -sss` -gt 0 ]; then
COLUMNS_PRIV=" UPDATE mysql.columns_priv set db='$3' WHERE db='$2';"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.procs_priv where db='$2'" -sss` -gt 0 ]; then
PROCS_PRIV=" UPDATE mysql.procs_priv set db='$3' WHERE db='$2';"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.tables_priv where db='$2'" -sss` -gt 0 ]; then
TABLES_PRIV=" UPDATE mysql.tables_priv set db='$3' WHERE db='$2';"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.db where db='$2'" -sss` -gt 0 ]; then
DB_PRIV=" UPDATE mysql.db set db='$3' WHERE db='$2';"
fi
if [ -n "$COLUMNS_PRIV" ] || [ -n "$PROCS_PRIV" ] || [ -n "$TABLES_PRIV" ] || [ -n "$DB_PRIV" ]; then
echo "IF YOU WANT TO RENAME the GRANTS YOU NEED TO RUN ALL OUTPUT BELOW:"
if [ -n "$COLUMNS_PRIV" ]; then echo "$COLUMNS_PRIV"; fi
if [ -n "$PROCS_PRIV" ]; then echo "$PROCS_PRIV"; fi
if [ -n "$TABLES_PRIV" ]; then echo "$TABLES_PRIV"; fi
if [ -n "$DB_PRIV" ]; then echo "$DB_PRIV"; fi
echo " flush privileges;"
fi
Most of the answers here are wrong for one of two reasons:
You cannot just use RENAME TABLE, because there might be views and triggers. If there are triggers, RENAME TABLE fails
You cannot use mysqldump if you want to "quickly" (as requested in the question) rename a big database
Percona has a blog post about how to do this well:
https://www.percona.com/blog/2013/12/24/renaming-database-schema-mysql/
and script posted (made?) by Simon R Jones that does what is suggested in that post. I fixed a bug I found in the script. You can see it here:
https://gist.github.com/ryantm/76944318b0473ff25993ef2a7186213d
Here is a copy of it:
#!/bin/bash
# Copyright 2013 Percona LLC and/or its affiliates
# #see https://www.percona.com/blog/2013/12/24/renaming-database-schema-mysql/
set -e
if [ -z "$3" ]; then
echo "rename_db <server> <database> <new_database>"
exit 1
fi
db_exists=`mysql -h $1 -e "show databases like '$3'" -sss`
if [ -n "$db_exists" ]; then
echo "ERROR: New database already exists $3"
exit 1
fi
TIMESTAMP=`date +%s`
character_set=`mysql -h $1 -e "SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = '$2'" -sss`
TABLES=`mysql -h $1 -e "select TABLE_NAME from information_schema.tables where table_schema='$2' and TABLE_TYPE='BASE TABLE'" -sss`
STATUS=$?
if [ "$STATUS" != 0 ] || [ -z "$TABLES" ]; then
echo "Error retrieving tables from $2"
exit 1
fi
echo "create database $3 DEFAULT CHARACTER SET $character_set"
mysql -h $1 -e "create database $3 DEFAULT CHARACTER SET $character_set"
TRIGGERS=`mysql -h $1 $2 -e "show triggers\G" | grep Trigger: | awk '{print $2}'`
VIEWS=`mysql -h $1 -e "select TABLE_NAME from information_schema.tables where table_schema='$2' and TABLE_TYPE='VIEW'" -sss`
if [ -n "$VIEWS" ]; then
mysqldump -h $1 $2 $VIEWS > /tmp/${2}_views${TIMESTAMP}.dump
fi
mysqldump -h $1 $2 -d -t -R -E > /tmp/${2}_triggers${TIMESTAMP}.dump
for TRIGGER in $TRIGGERS; do
echo "drop trigger $TRIGGER"
mysql -h $1 $2 -e "drop trigger $TRIGGER"
done
for TABLE in $TABLES; do
echo "rename table $2.$TABLE to $3.$TABLE"
mysql -h $1 $2 -e "SET FOREIGN_KEY_CHECKS=0; rename table $2.$TABLE to $3.$TABLE"
done
if [ -n "$VIEWS" ]; then
echo "loading views"
mysql -h $1 $3 < /tmp/${2}_views${TIMESTAMP}.dump
fi
echo "loading triggers, routines and events"
mysql -h $1 $3 < /tmp/${2}_triggers${TIMESTAMP}.dump
TABLES=`mysql -h $1 -e "select TABLE_NAME from information_schema.tables where table_schema='$2' and TABLE_TYPE='BASE TABLE'" -sss`
if [ -z "$TABLES" ]; then
echo "Dropping database $2"
mysql -h $1 $2 -e "drop database $2"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.columns_priv where db='$2'" -sss` -gt 0 ]; then
COLUMNS_PRIV=" UPDATE mysql.columns_priv set db='$3' WHERE db='$2';"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.procs_priv where db='$2'" -sss` -gt 0 ]; then
PROCS_PRIV=" UPDATE mysql.procs_priv set db='$3' WHERE db='$2';"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.tables_priv where db='$2'" -sss` -gt 0 ]; then
TABLES_PRIV=" UPDATE mysql.tables_priv set db='$3' WHERE db='$2';"
fi
if [ `mysql -h $1 -e "select count(*) from mysql.db where db='$2'" -sss` -gt 0 ]; then
DB_PRIV=" UPDATE mysql.db set db='$3' WHERE db='$2';"
fi
if [ -n "$COLUMNS_PRIV" ] || [ -n "$PROCS_PRIV" ] || [ -n "$TABLES_PRIV" ] || [ -n "$DB_PRIV" ]; then
echo "IF YOU WANT TO RENAME the GRANTS YOU NEED TO RUN ALL OUTPUT BELOW:"
if [ -n "$COLUMNS_PRIV" ]; then echo "$COLUMNS_PRIV"; fi
if [ -n "$PROCS_PRIV" ]; then echo "$PROCS_PRIV"; fi
if [ -n "$TABLES_PRIV" ]; then echo "$TABLES_PRIV"; fi
if [ -n "$DB_PRIV" ]; then echo "$DB_PRIV"; fi
echo " flush privileges;"
fi
Save it to a file called rename_db and make the script executable with chmod +x rename_db then use it like ./rename_db localhost old_db new_db
For those who are Mac users, Sequel Pro has a Rename Database option in the Database menu.
http://www.sequelpro.com/
Seems noone mentioned this but here is another way:
create database NewDatabaseName like OldDatabaseName;
then for each table do:
create NewDatabaseName.tablename like OldDatabaseName.tablename;
insert into NewDataBaseName.tablename select * from OldDatabaseName.tablename;
then, if you want to,
drop database OldDatabaseName;
This approach would have the advantage of doing the entire transfer on server with near zero network traffic, so it will go a lot faster than a dump/restore.
If you do have stored procedures/views/etc you might want to transfer them as well.
For mac users, you can use Sequel Pro (free), which just provide the option to rename Databases. Though it doesn't delete the old DB.
once open the relevant DB just click: Database --> Rename database...
It is possible to rename all tables within a database to be under another database without having to do a full dump and restore.
DROP PROCEDURE IF EXISTS mysql.rename_db;
DELIMITER ||
CREATE PROCEDURE mysql.rename_db(IN old_db VARCHAR(100), IN new_db VARCHAR(100))
BEGIN
SELECT CONCAT('CREATE DATABASE ', new_db, ';') `# create new database`;
SELECT CONCAT('RENAME TABLE `', old_db, '`.`', table_name, '` TO `', new_db, '`.`', table_name, '`;') `# alter table` FROM information_schema.tables WHERE table_schema = old_db;
SELECT CONCAT('DROP DATABASE `', old_db, '`;') `# drop old database`;
END||
DELIMITER ;
$ time mysql -uroot -e "call mysql.rename_db('db1', 'db2');" | mysql -uroot
However any triggers in the target db will not be happy. You'll need to drop them first then recreate them after the rename.
mysql -uroot -e "call mysql.rename_db('test', 'blah2');" | mysql -uroot
ERROR 1435 (HY000) at line 4: Trigger in wrong schema
Here is a batch file I wrote to automate it from the command line, but it for Windows/MS-DOS.
Syntax is rename_mysqldb database newdatabase -u [user] -p[password]
:: ***************************************************************************
:: FILE: RENAME_MYSQLDB.BAT
:: ***************************************************************************
:: DESCRIPTION
:: This is a Windows /MS-DOS batch file that automates renaming a MySQL database
:: by using MySQLDump, MySQLAdmin, and MySQL to perform the required tasks.
:: The MySQL\bin folder needs to be in your environment path or the working directory.
::
:: WARNING: The script will delete the original database, but only if it successfully
:: created the new copy. However, read the disclaimer below before using.
::
:: DISCLAIMER
:: This script is provided without any express or implied warranties whatsoever.
:: The user must assume the risk of using the script.
::
:: You are free to use, modify, and distribute this script without exception.
:: ***************************************************************************
:INITIALIZE
#ECHO OFF
IF [%2]==[] GOTO HELP
IF [%3]==[] (SET RDB_ARGS=--user=root) ELSE (SET RDB_ARGS=%3 %4 %5 %6 %7 %8 %9)
SET RDB_OLDDB=%1
SET RDB_NEWDB=%2
SET RDB_DUMPFILE=%RDB_OLDDB%_dump.sql
GOTO START
:START
SET RDB_STEP=1
ECHO Dumping "%RDB_OLDDB%"...
mysqldump %RDB_ARGS% %RDB_OLDDB% > %RDB_DUMPFILE%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR_ABORT
SET RDB_STEP=2
ECHO Creating database "%RDB_NEWDB%"...
mysqladmin %RDB_ARGS% create %RDB_NEWDB%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR_ABORT
SET RDB_STEP=3
ECHO Loading dump into "%RDB_NEWDB%"...
mysql %RDB_ARGS% %RDB_NEWDB% < %RDB_DUMPFILE%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR_ABORT
SET RDB_STEP=4
ECHO Dropping database "%RDB_OLDDB%"...
mysqladmin %RDB_ARGS% drop %RDB_OLDDB% --force
IF %ERRORLEVEL% NEQ 0 GOTO ERROR_ABORT
SET RDB_STEP=5
ECHO Deleting dump...
DEL %RDB_DUMPFILE%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR_ABORT
ECHO Renamed database "%RDB_OLDDB%" to "%RDB_NEWDB%".
GOTO END
:ERROR_ABORT
IF %RDB_STEP% GEQ 3 mysqladmin %RDB_ARGS% drop %NEWDB% --force
IF %RDB_STEP% GEQ 1 IF EXIST %RDB_DUMPFILE% DEL %RDB_DUMPFILE%
ECHO Unable to rename database "%RDB_OLDDB%" to "%RDB_NEWDB%".
GOTO END
:HELP
ECHO Renames a MySQL database.
ECHO Usage: %0 database new_database [OPTIONS]
ECHO Options: Any valid options shared by MySQL, MySQLAdmin and MySQLDump.
ECHO --user=root is used if no options are specified.
GOTO END
:END
SET RDB_OLDDB=
SET RDB_NEWDB=
SET RDB_ARGS=
SET RDB_DUMP=
SET RDB_STEP=
For your convenience, below is a small shellscript that has to be executed with two parameters: db-name and new db-name.
You might need to add login-parameters to the mysql-lines if you don't use the .my.cnf-file in your home-directory. Please make a backup before executing this script.
#!/usr/bin/env bash
mysql -e "CREATE DATABASE $2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;"
for i in $(mysql -Ns $1 -e "show tables");do
echo "$1.$i -> $2.$i"
mysql -e "rename TABLE $1.$i to $2.$i"
done
mysql -e "DROP DATABASE $1"
The simplest method is to use HeidiSQL software. It's free and open source. It runs on Windows and on any Linux with Wine (run Windows applications on Linux, BSD, Solaris and Mac OS X).
To download HeidiSQL, goto http://www.heidisql.com/download.php.
To download Wine, goto http://www.winehq.org/.
To rename a database in HeidiSQL, just right click on the database name and select 'Edit'. Then enter a new name and press 'OK'.
It is so simple.
TodoInTX's stored procedure didn't quite work for me. Here's my stab at it:
-- stored procedure rename_db: Rename a database my means of table copying.
-- Caveats:
-- Will clobber any existing database with the same name as the 'new' database name.
-- ONLY copies tables; stored procedures and other database objects are not copied.
-- Tomer Altman (taltman#ai.sri.com)
delimiter //
DROP PROCEDURE IF EXISTS rename_db;
CREATE PROCEDURE rename_db(IN old_db VARCHAR(100), IN new_db VARCHAR(100))
BEGIN
DECLARE current_table VARCHAR(100);
DECLARE done INT DEFAULT 0;
DECLARE old_tables CURSOR FOR select table_name from information_schema.tables where table_schema = old_db;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET #output = CONCAT('DROP SCHEMA IF EXISTS ', new_db, ';');
PREPARE stmt FROM #output;
EXECUTE stmt;
SET #output = CONCAT('CREATE SCHEMA IF NOT EXISTS ', new_db, ';');
PREPARE stmt FROM #output;
EXECUTE stmt;
OPEN old_tables;
REPEAT
FETCH old_tables INTO current_table;
IF NOT done THEN
SET #output = CONCAT('alter table ', old_db, '.', current_table, ' rename ', new_db, '.', current_table, ';');
PREPARE stmt FROM #output;
EXECUTE stmt;
END IF;
UNTIL done END REPEAT;
CLOSE old_tables;
END//
delimiter ;
There is a reason you cannot do this. (despite all the attempted answers)
Basic answers will work in many cases, and in others cause data corruptions.
A strategy needs to be chosen based on heuristic analysis of your database.
That is the reason this feature was implemented, and then removed. [doc]
You'll need to dump all object types in that database, create the newly named one and then import the dump. If this is a live system you'll need to take it down. If you cannot, then you will need to setup replication from this database to the new one.
If you want to see the commands that could do this, #satishD has the details, which conveys some of the challenges around which you'll need to build a strategy that matches your target database.
In MySQL Administrator do the following:
Under Catalogs, create a new database schema.
Go to Backup and create a backup of
the old schema.
Execute backup.
Go to Restore and open the file
created in step 3.
Select 'Another Schema' under Target
Schema and select the new database
schema.
Start Restore.
Verify new schema and, if it looks
good, delete the old one.
in phpmyadmin you can easily rename the database
select database
goto operations tab
in that rename Database to :
type your new database name and click go
ask to drop old table and reload table data click OK in both
Your database is renamed
Here is a quick way to generate renaming sql script, if you have many tables to move.
SELECT DISTINCT CONCAT('RENAME TABLE ', t.table_schema,'.', t.table_name, ' TO ',
t.table_schema, "_archive", '.', t.table_name, ';' ) as Rename_SQL
FROM information_schema.tables t
WHERE table_schema='your_db_name' ;
Here is a one-line Bash snippet to move all tables from one schema to another:
history -d $((HISTCMD-1)) && mysql -udb_user -p'db_password' -Dold_schema -ABNnqre'SHOW TABLES;' | sed -e's/.*/RENAME TABLE old_schema.`&` TO new_schema.`&`;/' | mysql -udb_user -p'db_password' -Dnew_schema
The history command at the start simply ensures that the MySQL commands containing passwords aren't saved to the shell history.
Make sure that db_user has read/write/drop permissions on the old schema, and read/write/create permissions on the new schema.
ALTER DATABASE is the proposed way around this by MySQL and RENAME DATABASE is dropped.
From 13.1.32 RENAME DATABASE Syntax:
RENAME {DATABASE | SCHEMA} db_name TO new_db_name;
This statement was added in MySQL 5.1.7, but it was found to be dangerous and was removed in MySQL 5.1.23.
I did it this way:
Take backup of your existing database. It will give you a db.zip.tmp and then in command prompt write following
"C:\Program Files (x86)\MySQL\MySQL Server 5.6\bin\mysql.exe" -h
localhost -u root -p[password] [new db name] < "C:\Backups\db.zip.tmp"
This works for all databases and works by renaming each table with maatkit mysql toolkit
Use mk-find to print and rename each table. The man page has many more options and examples
mk-find --dblike OLD_DATABASE --print --exec "RENAME TABLE %D.%N TO NEW_DATABASE.%N"
If you have maatkit installed (which is very easy), then this is the simplest way to do it.
Related
I would like to write a *.sh script to execute multiple MySQL commands.
Currently, what I can do is something like the following
mysql -h$host -u$user -p$password -e "drop database $dbname;"
mysql -h$host -u$user -p$password -e "create database $dbname;"
mysql -h$host -u$user -p$password -e "another MySQL command"
...
Is there a way to avoid typing mysql -h$host -u$user -p$password -e every time I want to execute a MySQL command?
I think you can execute MySQL statements from a text file, for example
here is the cmds.txt file which contains MySQL commands:
select colA from TableA;
select colB from TableB;
select colC from TableC;
To execute them using shell script, type
mysql -h$host -u$user -p$password db_dbname < cmds.txt
This way, you separate your MySQL commands from your shell script.
You may want your script to display progress information to you. For this you can invoke mysql with "--verbose" option.
For more information, see https://dev.mysql.com/doc/refman/5.6/en/mysql-batch-commands.html
You can use a single multiquery:
mysql -h$host -u$user -p$password -e "drop database $dbname;create database $dbname;another MySQL command;"
Simply write all your queries seperated by ;. They will be run one after the other.
Note that you can also use a HERE doc to have the queries within the same script:
mysql -h$host -u$user -p$password db_dbname <<'EOF'
select colA from TableA;
select colB from TableB;
select colC from TableC;
EOF
Note that I've used 'EOF' rather than EOF in the first line in order to prevent the contents of the script to disable parameter substitution (especially the ` can be problematic)
Also note that there should not be any whitespace before the final EOF (except if you use <<- rather than << -- in that case leading tab characters are stripped):
mysql -h$host -u$user -p$password db_dbname <<- 'EOF'
↠select colA from TableA;
↠select colB from TableB;
↠select colC from TableC;
↠EOF
(Replace the ↠ with a tab character).
For more info on the HERE doc syntax, see the bash documentation.
There are several ways, in linux you have:
From the mysql cli:
mysql> source mycmds.sql
Using Pipes:
echo "SELECT ..; INSERT ..;" | mysql ...
Executing commands from a file using pipes or redirection:
cat file.sql | mysql ... OR mysql .. < file.sql
Different from other answers that reduce repetition, but
there are ways to reduce options(user, host ... -u, -p, -h ...) from each line command
2 ways i know.
1. use my.cnf file
you can store your user information in option files (e.g ~/.my.cnf or etc)
[client]
user=your_username
password=your_password
# database=database_name
then you can just run mysql command with one option -e and query
mysql -e "drop database $dbname;"
mysql -e "create database $dbname;"
mysql -e "another MySQL command"
2. use mysql_config_editor
you can save login informations with mysql_config_editor
mysql_config_editor set --login-path=mypath1 --host=localhost --user=root --password
then run command just with login-path option
mysql --login-path=mypath1 -e "drop database $dbname;"
mysql --login-path=mypath1 -e "create database $dbname;"
mysql --login-path=mypath1 -e "another MySQL command"
MySQL has an OPTIMIZE TABLE command which can be used to reclaim unused space in a MySQL install. Is there a way (built-in command or common stored procedure) to run this optimization for every table in the database and/or server install, or is this something you'd have to script up yourself?
You can use mysqlcheck to do this at the command line.
One database:
mysqlcheck -o <db_schema_name>
All databases:
mysqlcheck -o --all-databases
I made this 'simple' script:
set #tables_like = null;
set #optimize = null;
set #show_tables = concat("show tables where", ifnull(concat(" `Tables_in_", database(), "` like '", #tables_like, "' and"), ''), " (#optimize:=concat_ws(',',#optimize,`Tables_in_", database() ,"`))");
Prepare `bd` from #show_tables;
EXECUTE `bd`;
DEALLOCATE PREPARE `bd`;
set #optimize := concat('optimize table ', #optimize);
PREPARE `sql` FROM #optimize;
EXECUTE `sql`;
DEALLOCATE PREPARE `sql`;
set #show_tables = null, #optimize = null, #tables_like = null;
To run it, simply paste it in any SQL IDE connected to your database.
Notice: this code WON'T work on phpmyadmin.
How it works
It runs a show tables statement and stores it in a prepared statement. Then it runs a optimize table in the selected set.
You can control which tables to optimize by setting a different value in the var #tables_like (e.g.: set #tables_like = '%test%';).
Following example php script can help you to optimize all tables in your database
<?php
dbConnect();
$alltables = mysql_query("SHOW TABLES");
while ($table = mysql_fetch_assoc($alltables))
{
foreach ($table as $db => $tablename)
{
mysql_query("OPTIMIZE TABLE '".$tablename."'")
or die(mysql_error());
}
}
?>
If you want to analyze, repair and optimize all tables in all databases in your MySQL server, you can do this in one go from the command line. You will need root to do that though.
mysqlcheck -u root -p --auto-repair --optimize --all-databases
Once you run that, you will be prompted to enter your MySQL root password. After that, it will start and you will see results as it's happening.
Example output:
yourdbname1.yourdbtable1 OK
yourdbname2.yourdbtable2 Table is already up to date
yourdbname3.yourdbtable3
note : Table does not support optimize, doing recreate + analyze instead
status : OK
etc..
etc...
Repairing tables
yourdbname10.yourdbtable10
warning : Number of rows changed from 121378 to 81562
status : OK
If you don't know the root password and are using WHM, you can change it from within WHM by going to:
Home > SQL Services > MySQL Root Password
Do all the necessary procedures for fixing all tables in all the databases with a simple shell script:
#!/bin/bash
mysqlcheck --all-databases
mysqlcheck --all-databases -o
mysqlcheck --all-databases --auto-repair
mysqlcheck --all-databases --analyze
From phpMyAdmin and other sources/editors you can use:
SET SESSION group_concat_max_len = 99999999;
SELECT GROUP_CONCAT(concat('OPTIMIZE TABLE `', table_name, '`;') SEPARATOR '') AS O
FROM INFORMATION_SCHEMA.TABLES WHERE
TABLE_TYPE = 'BASE TABLE'
AND table_name!='dual'
AND TABLE_SCHEMA = '<your databasename>'
Then you can copy & paste the result to a new query or execute it from your own source.
If you don't see the whole statement in phpMyAdmin:
for all databases:
mysqlcheck -Aos -uuser -p
For one Database optimization:
mysqlcheck -os -uroot -p dbtest3
From command line:
mysqlcheck -o <db_name> -u<username> -p
then type password
You can optimize/check and repair all the tables of database, using mysql client.
First, you should get all the tables list, separated with ',':
mysql -u[USERNAME] -p[PASSWORD] -Bse 'show tables' [DB_NAME]|xargs|perl -pe 's/ /,/g'
Now, when you have all the tables list for optimization:
mysql -u[USERNAME] -p[PASSWORD] -Bse 'optimize tables [tables list]' [DB_NAME]
my 1 cent, added and TABLE_TYPE='BASE TABLE' so we can skip the 'VIEW' type.
for table in `mysql -sss -e "select concat(table_schema,'.',table_name) from information_schema.tables where table_schema not in ('mysql','information_schema','performance_schema') and TABLE_TYPE='BASE TABLE' order by data_free desc;"`
do
mysql -e "OPTIMIZE TABLE $table;"
done
The MySQL Administrator (part of the MySQL GUI Tools) can do that for you on a database level.
Just select your schema and press the Maintenance button in the bottom right corner.
Since the GUI Tools have reached End-of-life status they are hard to find on the mysql page. Found them via Google: http://dev.mysql.com/downloads/gui-tools/5.0.html
I don't know if the new MySQL Workbench can do that, too.
And you can use the mysqlcheck command line tool which should be able to do that, too.
A starter bash script to list and run a tool against the DBs...
#!/bin/bash
declare -a dbs
unset opt
for each in $(echo "show databases;" | mysql -u root) ;do
dbs+=($each)
done
echo " The system found [ ${#dbs[#]} ] databases." ;sleep 2
echo
echo "press 1 to run a check"
echo "press 2 to run an optimization"
echo "press 3 to run a repair"
echo "press 4 to run check,repair, and optimization"
echo "press q to quit"
read input
case $input in
1) opt="-c"
;;
2) opt="-o"
;;
3) opt="-r"
;;
4) opt="--auto-repair -c -o"
;;
*) echo "Quitting Application .."; exit 7
;;
esac
[[ -z $opt ]] && exit 7;
echo " running option: mysqlcheck $opt in 5 seconds on all Dbs... "; sleep 5
for ((i=0; i<${#dbs[#]}; i++)) ;do
echo "${dbs[$i]} : "
mysqlcheck $opt ${dbs[$i]} -u root
done
If you are accessing database directly then you can write following query:
OPTIMIZE TABLE table1,table2,table3,table4......;
This bash script will accept the root password as option and optimize it one by one, with status output:
#!/bin/bash
if [ -z "$1" ] ; then
echo
echo "ERROR: root password Parameter missing."
exit
fi
MYSQL_USER=root
MYSQL_PASS=$1
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
TBLLIST=""
COMMA=""
SQL="SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE"
SQL="${SQL} table_schema NOT IN ('information_schema','mysql','performance_schema')"
for DBTB in `mysql ${MYSQL_CONN} -ANe"${SQL}"`
do
echo OPTIMIZE TABLE "${DBTB};"
SQL="OPTIMIZE TABLE ${DBTB};"
mysql ${MYSQL_CONN} -ANe"${SQL}"
done
my 2cents: start with table with highest fragmentation
for table in `mysql -sss -e "select concat(table_schema,".",table_name) from information_schema.tables where table_schema not in ('mysql','information_schema','performance_schema') order by data_free desc;"
do
mysql -e "OPTIMIZE TABLE $table;"
done
If local moderators allow this, I would like to promote a PHP library I wrote quite some time ago - https://github.com/Simbiat/optimize-tables
The point of the library is to allow "smart" execution of the OPTIMIZE, ANALYZE, CHECK and REPAIR commands depending on table's parameters and statistics. I've been running it in CRON for https://simbiat.ru for over 2 years now and it has been smooth sailing (aside from some adjustments and minor fixes, of course).
Why would you want to use something like this? Well, the README provides some more details, but in short, it can help with running relevant operations only when you can actually benefit from them. At the least, it can save your resources.
I want to drop all the databases starting with a word.
abc
xyz
cms_db1
cms_db2
cms_xyz
pqr
In the example given above, I will like to drop all the Databases starting with the word "cms".
I guess maatkit or shell script can do it. What is the best approach?
Here's a pure mySQL solution in two queries:
SELECT CONCAT('DROP DATABASE `', SCHEMA_NAME, '`;')
FROM `information_schema`.`SCHEMATA`
WHERE SCHEMA_NAME LIKE 'cms_%';
Then copy and paste the resulting recordset and run
I had to improve neurinos script because of special chars in my password, missing 'drop DATABASE ...' and not working comparision for DB_STARTS_WITH expression. The following script did work on Ubuntu Server:
#!/bin/bash
DB_STARTS_WITH="grp"
MUSER="root"
MPWD="YOUR_PASSWORD"
MYSQL="mysql"
DBS="$($MYSQL -u $MUSER -p"$MPWD" -Bse 'show databases')"
for db in $DBS; do
if [[ "$db" == $DB_STARTS_WITH* ]]; then
echo "Deleting $db"
$MYSQL -u $MUSER -p"$MPWD" -Bse "drop database $db"
fi
done
I would use something like:
echo "SHOW DATABASES LIKE 'cms_%'" \
| mysql \
| tail -n +2 \
| xargs -n1 mysqladmin -f drop
If you don't have your default username and password configured inside ~/my.cnf, you may need to supply the username and password via the -u and -p switches to the mysql/mysqladmin commands above.
(Edit - added -n arg to tail.)
Linux way:
#!/bin/bash
DB_STARTS_WITH="cms"
MUSER="root"
MPWD="yourpass"
MYSQL="mysql"
DBS="$($MYSQL -u$MUSER -p$MPWD -Bse 'show databases')"
for db in $DBS; do
if [[ "$db" =~ "^${DB_STARTS_WITH}" ]]; then
echo "Deleting $db"
$MYSQL -u$MUSER -p$MPWD -Bse "drop database $db"
fi
done
Of course use the drop part at your own risk ;)
If you wish to stay completely within MySQL/MariaDB (i.e. without using bash scripts and such) you can do the following:
DELIMITER //
CREATE PROCEDURE clean()
BEGIN
SET #query := (SELECT CONCAT('DROP DATABASE ', SCHEMA_NAME, ';') FROM `information_schema`.`SCHEMATA` WHERE SCHEMA_NAME LIKE 'dbtVDB%' LIMIT 1);
WHILE #query != '' DO
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #query := (SELECT CONCAT('DROP DATABASE ', SCHEMA_NAME, ';') FROM `information_schema`.`SCHEMATA` WHERE SCHEMA_NAME LIKE 'cms%' LIMIT 1);
END WHILE;
DELETE FROM mysql.db WHERE mysql.db.Db LIKE 'cms%';
END;
//
DELIMITER ;
CALL clean();
DROP PROCEDURE clean;
A Linux way:
for db_name in $(mysql -u USER -pPASS -e "show databases like 'cms_%'" -ss)
do
mysql -u USER -pPASS -e "drop database ${db_name}";
done
I liked the answer suggesting a "for" loop from the shell. In my case, I had subdirectory names matching my database names so I made arrays, then used them in the command.
(I could have done this using the mysql data directory come to think of it, even if I hadn't had the setup I had. On my bitnami VM this is
/opt/bitnami/mysql/data.)
created array from subset of files: tbtdirs=(tbt*2015*)
Tested a potentially spooky command first w/ "echo": for d in ${tbtdirs[#]}; do echo mysql -pPASS -e "drop database $d"; done
dropped all databases in the array: for d in ${tbtdirs[#]}; do mysql -pPASS -e "drop database $d"; done
Worked like a charm! Also modified the loop to remove subdirectories. I used Linux command line for quite some time before learning how useful the bash commands could be.
Using #léo-alves-de-araujo I have modified it to ask the user/password (More secure way) from command line (with linux)
#!/bin/bash
echo -n "Enter Mysql User:"
read user
echo -n "Enter Mysql Password:"
read -s password
for db_name in $(mysql -u $user --password=$password -e "SHOW DATABASES LIKE 'cms_%'" -ss 2>/dev/null)
do
mysql -u $user --password=$password -e "DROP DATABASE ${db_name}" 2>/dev/null;
done
Improved #neurino solution to avoid storing of MySQL credentials in the script and passing them through a command line (it might be visible in the list of processes then)
#!/bin/bash
DB_STARTS_WITH="cms"
MYSQL="mysql"
read -p "Enter MySQL user name: " MYSQL_USER
read -s -p "Enter password: " MYSQL_PASSWORD
CREDENTIALS_FILE="$(mktemp)"
chmod 600 $CREDENTIALS_FILE
cat > $CREDENTIALS_FILE <<- EOM
[client]
user=$MYSQL_USER
password=$MYSQL_PASSWORD
EOM
trap "{ rm -f $CREDENTIALS_FILE; }" EXIT
DATABASES="$(echo "show databases;" | $MYSQL --defaults-file=$CREDENTIALS_FILE)"
for DATABASE in $DATABASES; do
if [[ $DATABASE =~ ^${DB_STARTS_WITH} ]]; then
echo Removing $DATABASE...
echo "drop database $DATABASE" | $MYSQL --defaults-file=$CREDENTIALS_FILE
fi
done
Improvising on the excellent answer by #cloakedninjas, for easier retrieval of all the queries to execute in a single string.
Firstly, you can set the maximum value for group_concat_max_len to the maximum possible value, for this particular session:
SET SESSION group_concat_max_len = ##max_allowed_packet;
Now, you can prepare a query string (to execute later) using SQL. Using information_schema, we can get name of all the databases matching the pattern. Now, use Concat() to prepare a single DROP DATABASE .. query, and then utilize Group_Concat() to merge them all into a single string, for easier retrieval.
SELECT GROUP_CONCAT(CONCAT('DROP DATABASE `', SCHEMA_NAME, '`;')
SEPARATOR ' ') AS query_to_execute
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME LIKE 'cms_%'
Now copy the string in query_to_execute and run it separately.
So we have a lot of routines that come out from exporting. We often need to get these out in CLI, make changes, and bring them back in. Yes, some of these are managed by different folks and a better change control is required, but for now this is the situation.
If I do:
mysqldump --routines --no-create-info --no-data --no-create-db
then great, I have 200 functions. I need to go through a file to find just the one or set I want.
Is there anyway to mysqldump routines that I want like there is for tables?
Another way to go about this would be the following. Do note, however, that you have to have root privileges in the target database in order to import rows into mysql.proc:
mysqldump --compact --no-create-info --where="db='yourdatabasename' AND type='PROCEDURE' AND name IN ('yoursp1', 'yoursp2')" --databases mysql --tables proc
To answer your exact question: no.
But this will probably give you what you want.
Take a look at SHOW CREATE PROCEDURE and SHOW CREATE FUNCTION:
http://dev.mysql.com/doc/refman/5.0/en/show-create-procedure.html
http://dev.mysql.com/doc/refman/5.0/en/show-create-function.html
Those commands allow you to dump the code for one routine at a time.
It is possible to dump a single function or procedure using the command that Ike Walker mentioned, but the SHOW CREATE PROCEDURE and SHOW CREATE FUNCTION commands don't allow to select only a few columns from the output.
Here is a example of a Windows batch command line to dump a single procedure, using the system table mysql.proc:
mysql --defaults-extra-file=myconfig.cnf --skip-column-names --raw --batch mydatabase -e "SELECT CONCAT('DELIMITER $$\nCREATE PROCEDURE `', specific_name, '`(', param_list, ') AS \n', body_utf8, ' $$\nDELIMITER ;\n') AS `stmt` FROM `mysql`.`proc` WHERE `db` = 'mydatabase' AND specific_name = 'myprocedure';" 1> myprocedure.sql
This will redirect the output of mysql into the file myprocedure.sql.
The --batch option tells the mysql client to remove the table borders from the output.
The --skip-column-names option removes the column headers from the output.
The --raw option tells MySQL to not escape special characters on the output, keeping new lines as is instead of replacing them with \n.
And if you want to dump ALL the procedures in different files, this example in batch should work:
dump-procedures.bat
#echo off
REM set the target database
set database=mydatabase
REM set the connection configuration file
set auth=--defaults-extra-file=myconfig.cnf
REM set the routine type you want to dump
set routine_type=PROCEDURE
set list_file=%routine_type%S.csv
if "%routine_type%"=="PROCEDURE" (
set ending=AS
)
if "%routine_type%"=="FUNCTION" (
set ending=RETURNS ', `returns`, '
)
echo Dumping %routine_type% list to %list_file%
mysql %auth% --skip-column-names --raw %database% -e "SELECT routine_name FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = DATABASE() AND ROUTINE_TYPE = '%routine_type%';" 1> %list_file%
for /f "tokens=*" %%a in (%list_file%) do (
echo Dumping %routine_type% %%a
mysql %auth% --skip-column-names --raw --batch %database% -e "SELECT CONCAT('DELIMITER $$\nCREATE PROCEDURE `', specific_name, '`(', param_list, ') %ending% \n', body_utf8, ' $$\nDELIMITER ;\n') AS `stmt` FROM `mysql`.`proc` WHERE `db` = '%database%' AND specific_name = '%%a';" 1> %%a.sql
)
It works in 2 steps, where it first dumps the list of all procedures into the file procedures.csv, and then iterates in each line and uses the names of the procedures to dump each procedure in a different file.
In this example, I am also using the option --defaults-extra-file, where some configuration parameters are set in a different file, and allows to invoke the command without needing to type the password each time or writing the password inside the batch itself. I created a file with this content
myconfig.cnf
[client]
host=localhost
port=3306
user=myusername
password=mypassword
This solution also works with function, defining the routine_type variable to:
set routine_type=FUNCTION
I have written the solution within bash.
For one procedure
mysql -NB -u root my_database -e 'show create procedure `myProcedure`' |\
xargs -n 1 -d '\t' echo |\
egrep '^CREATE' |\
xargs --null echo -e >
For all procedures
mysql -NB -u root -e 'SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = "my_database" AND ROUTINE_TYPE = "PROCEDURE"' |\
xargs -n 1 -I {} mysql -NB -u root my_database -e 'show create procedure `{}`' |\
xargs -n 1 -d '\t' echo |\
egrep '^CREATE' |\
xargs --null echo -e
This is trick,
create DATABASE to local.
dump your DATABASE include your STORE PROCEDURE to local.
or
just use mysql*yog and copy database, check STORE PROCEDURE (example: 1 store procedure) to local server.
dump your DATABASE local . yeah, you have 1 store procedure in your dump. remember use --routine if u want sp/events only.
trick is fun, isn't lazy, just tricked.
I want to back up only the Views with mysqldump.
Is this possible?
If so, how?
NOTE: This answer from Ken moved from suggested edit to own answer.
here's a full command line example using a variant of the above
mysql -u username INFORMATION_SCHEMA
--skip-column-names --batch
-e "select table_name from tables where table_type = 'VIEW'
and table_schema = 'database'"
| xargs mysqldump -u username database
> views.sql
This extracts all of the view names via a query to the INFORMATION_SCHEMA database, then pipes them to xargs to formulate a mysqldump command. --skip-column-names and --batch are needed to make the output xargs friendly. This command line might get too long if you have a lot of views, in which case you'd want to add some sort of additional filter to the select (e.g. look for all views starting with a given character).
Backing up views over multiple databases can be done by just using information_schema:
mysql --skip-column-names --batch -e 'select CONCAT("DROP TABLE IF EXISTS ", TABLE_SCHEMA, ".", TABLE_NAME, "; CREATE OR REPLACE VIEW ", TABLE_SCHEMA, ".", TABLE_NAME, " AS ", VIEW_DEFINITION, "; ") table_name from information_schema.views'
I modified Andomar's excellent answer to allow the database (and other settings) to only be specified once:
#!/bin/bash -e
mysql --skip-column-names --batch -e \
"select table_name from information_schema.views \
where table_schema = database()" $* |
xargs --max-args 1 mysqldump $*
I save this as mysql-dump-views.sh and call it via:
$ mysql-dump-views.sh -u user -ppassword databasename >dumpfile.sql
By backup, I'm assuming you mean just the definition without the data.
It seems that right now mysqldump doesn't distinguish between VIEWs and TABLEs, so perhaps the best thing to do is to either specify the VIEWs explicitly on the command line to mysqldump or figure out this list dynamically before mysqldump and then passing it down like before.
You can get all the VIEWs in a specific database using this query:
SHOW FULL TABLES WHERE table_type='view';
In terms of answering this question, olliiiver's answer is the best for doing this directly. For my answer I will try to build that into a comprehensive full backup and restore solution.
With the help of the other answers in this question, and a few other resources, I came up with this script for easily replacing the database on my development server with a live copy from the production server on demand. It works on one database at a time, rather than all databases. While I do have a separate script for that, it is not safe to share here as it basically drops and recreates everything except for a select few databases, and your environment may vary.
The script assumes root system and MySQL user on both machines (though that can be changed), working passwordless SSH between servers, and relies on a MySQL password file /root/mysqlroot.cnf on each machine, which looks like this:
[client]
password=YourPasswordHere
File: synctestdb.sh, optionally symlinked to /usr/sbin/synctestdb for ease of use
Usage: synctestdb DBNAME DESTSERVER
Run it from the production server.
Here it is:
#!/bin/bash
if [ "${1}" != "" ] && [ "${1}" != "--help" ] && [ "${2}" != "" ] ; then
DBNAME=${1}
DESTSERVER=${2}
BKDATE=$( date "+%Y-%m-%d" );
SRCHOSTNAME=$( /bin/hostname )
EXPORTPATH=/tmp
EXPORTFILE=/tmp/${SRCHOSTNAME}_sql_${BKDATE}_devsync.sql
CREDSFILE=/root/mysqlroot.cnf
SSHUSER=root
DBEXISTS=$( echo "SHOW DATABASES LIKE '${DBNAME}'" \
| mysql --defaults-extra-file=${CREDSFILE} -NB INFORMATION_SCHEMA )
if [ "${DBEXISTS}" == "${DBNAME}" ] ; then
echo Preparing --ignore-tables parameters for all relevant views
echo
#build --ignore-table parameters list from list of all views in
#relevant database - as mysqldump likes to recreate views as tables
#we pair this with an export of the view definitions later below
SKIPVIEWS=$(mysql --defaults-extra-file=${CREDSFILE} \
-NB \
-e "SELECT \
CONCAT( '--ignore-table=', TABLE_SCHEMA, '.', TABLE_NAME ) AS q \
FROM INFORMATION_SCHEMA.VIEWS \
WHERE TABLE_SCHEMA = '${DBNAME}';" )
if [ "$?" == "0" ] ; then
echo Exporting database ${DBNAME}
echo
mysqldump --defaults-extra-file=${CREDSFILE} ${SKIPVIEWS} \
--add-locks --extended-insert --flush-privileges --no-autocommit \
--routines --triggers --single-transaction --master-data=2 \
--flush-logs --events --quick --databases ${DBNAME} > ${EXPORTFILE} \
|| echo -e "\n\nERROR: ${SRCHOSTNAME} failed to mysqldump ${DBNAME}"
echo Exporting view definitions
echo
mysql --defaults-extra-file=${CREDSFILE} \
--skip-column-names --batch \
-e "SELECT \
CONCAT( \
'DROP TABLE IF EXISTS ', TABLE_SCHEMA, '.', TABLE_NAME, \
'; CREATE OR REPLACE VIEW ', TABLE_SCHEMA, '.', TABLE_NAME, ' AS ', \
VIEW_DEFINITION, '; ') AS TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS \
WHERE TABLE_SCHEMA = '${DBNAME}';" >> ${EXPORTFILE} \
|| echo -e "\n\nERROR: ${SRCHOSTNAME} failed to mysqldump view definitions"
echo Export complete, preparing to transfer export file and import
echo
STATUSMSG="SUCCESS: database ${DBNAME} synced from ${SRCHOSTNAME} to ${DESTSERVER}"
scp \
${EXPORTFILE} \
${SSHUSER}#${DESTSERVER}:${EXPORTPATH}/ \
|| STATUSMSG="ERROR: Failed to SCP file to remote server ${DESTSERVER}"
ssh ${SSHUSER}#${DESTSERVER} \
"mysql --defaults-extra-file=${CREDSFILE} < ${EXPORTFILE}" \
|| STATUSMSG="ERROR: Failed to update remote server ${DESTSERVER}"
ssh ${SSHUSER}#${DESTSERVER} \
"rm ${EXPORTFILE}" \
|| STATUSMSG="ERROR: Failed to remove import file from remote server ${DESTSERVER}"
rm ${EXPORTFILE}
echo ${STATUSMSG}
else
echo "ERROR: could not obtain list of views from INFORMATION_SCHEMA"
fi
else
echo "ERROR: specified database not found, or SQL credentials file not found"
fi
else
echo -e "Usage: synctestdb DBNAME DESTSERVER \nPlease only run this script from the live production server\n"
fi
So far it appears to work, though you may want to tweak it for your purposes. Be sure that wherever your credentials file is, it is set with secure access rights, so that unauthorized users cannot read it!
As it seems to be difficult to export views properly, I adapted olliiiver's answer to make it so that first we delete any tables or views with the exact names of valid views on the database we are importing into in case they exist, then importing all tables, which may erroneously create those views as tables, then delete those tables and define those views properly.
Basically here is how it works:
verify existence of the database you specified on the command line
use MYSQLDUMP to create a dump file
SCP the dump file from production to the specified test server
issue import commands on the specified test server over SSH and return output
remove dump file from both servers after complete
issue some reasonable output for most steps along the way
I would stick as closely as possible to the output of mysqldump like the OP asked, since it includes a slew of information about the view that can't be reconstructed with a simple query from the INFORMATION_SCHEMA.
This is how I create a deployment view script from my source database:
SOURCEDB="my_source_db"
mysql $SOURCEDB --skip-column-names -B -e \
"show full tables where table_type = 'view'" \
| awk '{print $1}' \
| xargs -I {} mysqldump $SOURCEDB {} > views.sql
Thanks for this - very useful.
One hiccup though - perhaps as I have a slightly convoluted set of views that reference other views etc:
I found that the "definer" user needs to exist and have the right permissions on the target schema, otherwise mysql will not generate the views that reference other views as it things definitions are insufficient.
In the generated:
/*!50013 DEFINER=<user>#<host> SQL SECURITY DEFINER */
--> ensure <user>#<host> is ok on your target instance, or replace this string with a user that does.
Thanks
Thorstein