I need to delete the data from all tables but one table in my database. Let's assumme the database is called my_database and the table in which data should be preserved is called my_important_table, so is there any way to achieve this?
I was able to figure out this problem thanks to these questions:
Truncate all tables in a MySQL database in one command? (check most voted answer)
mysql: What is the right syntax for NOT LIKE? (check validated answer)
The following command worked properly for me:
mysql -u root -p -Nse "SHOW TABLES WHERE \`Tables_in_my_database\` != 'my_important_table'" my_database | while read table; do echo "SET FOREIGN_KEY_CHECKS = 0; truncate table $table;"; done | mysql -u root -p my_database
The following command is the same as the previous one, but I split it into multiple lines to improve visualization.
mysql -u root -p -Nse "SHOW TABLES WHERE \`Tables_in_my_database\` != 'my_important_table'" my_database | \
while read table; do echo "SET FOREIGN_KEY_CHECKS = 0; truncate table $table;"; done | \
mysql -u root -p my_database
I am trying to run the following code from a linux (CentOS 7) terminal:
mysql -u root -p -e "SET FOREIGN_KEY_CHECKS = 0"; mysql -u root -p -Nse 'show tables' DATABASE_NAME -u root -p| while read table; do mysql -u root -p -e "truncate table $table" DATABASE_NAME; done;
But it apparently does not process the set foreign key checks command because in response I get:
ERROR 1701 (42000) at line 1: Cannot truncate a table referenced in a foreign key constraint (`atest`.`PARTICIPANT_2`, CONSTRAINT `FK_0a036647645f4e5e950470cb2dc` FOREIGN KEY (`PARTICIPANT_ACT_HJID`) REFERENCES `atest`.`ACT` (`HJID`))
Also, it continues to ask me for the password. I expect it to ask 3 times for the password, but not to repeat the three requests again and again. How can I change my code above to get it to run correctly, and with a minimal number of requests for password?
EDIT:
The following modification appears to be asking for the password for EVERY table in the loop. There are 500+ tables. How can I fix this so it only asks for the password a couple times?
mysql -u root -p -Nse 'show tables' DATABASE_NAME | while read table; do mysql -u root -p -e "SET FOREIGN_KEY_CHECKS = 0; truncate table $table" atest; done;
The foreign_key_checks is a session variable, it's in effect only for the current session, until it's changed, or until the session ends.
You are creating multiple database session, each new session starts with it's own foreign_key_checks variable, set to the default (inherited from the global setting). (I'm not going to mention how you change the default, because you do not really want to go there.)
One option would be to perform the SET FOREIGN_KEY_CHECKS statement in the same session as the TRUNCATE TABLE statement.
Use a semicolon as a statement separator. As a demonstration of running two statements:
mysql -u me -pXX -e "show variables like 'foreign%'; show variables like '%packet%';"
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.
This is what I currently have:
#!/bin/bash
# Shell script to backup MySql database
MyUSER="root"
MyPASS="password123"
MYSQL="$mysql"
MYSQLDUMP="$mysqldump"
# Store list of databases
DBS=""
# Get all database list first
DBS="$($MYSQL -u $MyUSER -h -p$MyPASS -Bse 'show databases')"
for db in $DBS
do
The problem i have is the 'do' bit,
I need to write this into the shell.
After getting all the DB names do the following:
updated user set password="passowrd" where id = 999;
Can anyone assist?
try
for db in $DBS
do
$MYSQL -u $MyUSER -h -p$MyPASS -Bse "update $db.password='password' whereid =999;'
end
as you can easily access a table by databasename.tablename in mysql.