繁体   English   中英

如何从 MySQL 数据库中删除所有空表?

[英]How do I drop all empty tables from a MySQL database?

如何从 MySQL 数据库中删除所有空表,只留下至少有 1 条记录的表?

编辑:这就是我在 mysqlclient 中使用 Python 3 所做的

import MySQLdb

conn = MySQLdb.connect(
    host='localhost', user='root',
    passwd='mypassword', db='mydatabase'
)

c = conn.cursor()
c.execute('SHOW TABLES')
for row in c.fetchall():
    table_name = row[0]
    c.execute(f'SELECT * FROM {table_name}')
    if c.rowcount == 0:
        # c.execute(f'DROP TABLE {table_name}')
        print(f'DROP TABLE {table_name}')

使用 Percona Toolkit 中的pt-find

$ pt-find --dblike "mydatabase" --empty --exec-plus "DROP TABLE %s"

这个存储过程应该这样做:

DELIMITER $$

DROP PROCEDURE IF EXISTS `drop_empty_tables_from` $$

CREATE PROCEDURE `drop_empty_tables_from`(IN schema_target VARCHAR(128))
BEGIN
    DECLARE table_list TEXT;
    DECLARE total      VARCHAR(11);

    SELECT
        GROUP_CONCAT(`TABLE_NAME`),
        COUNT(`TABLE_NAME`)
    INTO
        table_list,
        total
    FROM `information_schema`.`TABLES`
    WHERE
          `TABLE_SCHEMA` = schema_target
      AND `TABLE_ROWS`   = 0;

    IF table_list IS NOT NULL THEN
        SET @drop_tables = CONCAT("DROP TABLE ", table_list);

        PREPARE stmt FROM @drop_tables;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END IF;

    SELECT total AS affected_tables;
END $$

DELIMITER ;

当空表过多时, GROUP_CONCAT可能会出现问题。 这取决于group_concat_max_len系统变量的值。

由于DROP TABLE无法从SELECT查询接收其参数,因此不可能在一个查询中执行此操作。

InnoDB 注释

感谢詹姆斯的评论。 在 InnoDB 表的情况下,行计数查询似乎不会返回精确的结果,因此当该模式中有 InnoDB 表时,不能保证上述过程完美运行。

对于 InnoDB 表,行数只是 SQL 优化中使用的粗略估计。 (如果 InnoDB 表被分区,这也是正确的。)

来源: http : //dev.mysql.com/doc/refman/5.1/en/tables-table.html

和一个 PHP 版本的完整性。 它不会丢弃任何东西,只需为您打印 DROP 语句:

<?php
$username="root";
$password="mypassword";
$database="mydatabase";
mysql_connect('localhost',$username,$password);
mysql_select_db($database) or die( "Unable to select database");

function drop_empty_tables(){
    $tables = mysql_query('SHOW TABLES');
    while($table = mysql_fetch_array($tables)){
        $table = $table[0];
        $records = mysql_query("SELECT * FROM $table");
        if(mysql_num_rows($records) == 0){
            // mysql_query("DROP TABLE $table");
            echo "DROP TABLE $table;\n";
        }
    }
}

drop_empty_tables();
?>
  • 如果“空”表示带有“”的条目IF (SELECT * FROM tablexy) DROP TABLE tablexy
  • 如果“空”意味着没有任何条目IF (SELECT * FROM tablexy) DROP TABLE tablexy

(你必须为每个表运行这个查询,因为我没有找到一种方法在一个查询中对所有表执行一个查询)

这是相同的查询,但我想与 NOTHING 和 SOMETHING WITH NO CONTENT 不同;)

这是之前发布的 php 脚本的修改版本,
我添加了一个循环遍历所有数据库的函数(作为原始脚本,当你想真正运行脚本时,取消注释 mysql_query() )

<?php
$username="root";
$password="mypassword";
$database="information_schema";
mysql_connect('localhost',$username,$password);
mysql_select_db($database) or die( "Unable to select database\n");

function find_databases() {
// edit the query if you want to add more databases that you dont want to mess with
$databaseq = mysql_query("SELECT DISTINCT(SCHEMA_NAME) FROM SCHEMATA WHERE SCHEMA_NAME not in ('information_schema','mysql','phpmyadmin');");
    while($databaser = mysql_fetch_array($databaseq)){
        echo "Checking $databaser[0] ...\n";
            drop_empty_tables_and_db($databaser[0]);
    }
}

function drop_empty_tables_and_db($get_database){
    mysql_select_db($get_database) or print( "Unable to select database $get_databas\n");
    $tables = mysql_query('SHOW TABLES');
    while($table = mysql_fetch_array($tables)){
        $table = $table[0];
        $records = mysql_query("SELECT * FROM $table");
        if(mysql_num_rows($records) == 0){
            echo "DROP TABLE `$table`; \n";
            //mysql_query("DROP TABLE `$table`") or print( "Unable to drop table $table\n");
        }
    }
    $tables = mysql_query('SHOW TABLES');
    if(mysql_num_rows($tables) == 0){
        echo "DROP DATABASE `$get_database`;\n";
        //mysql_query("DROP DATABASE `$get_database`") or print( "Unable to drop database $get_database\n");
    }
}

find_databases(); //...and remove them :)

?>

如果直接从 shell 使用,请将 db 替换为 database_name。 请注意,这是实时的,无需取消注释。

db='wordpress_db';
for f in $(mysql -e "use $db;SHOW TABLES;" | sed 's/^| \([^ ]*\).*$/\1/g'|sed 1d);
do 
   c=`mysql -e "use $db;SELECT COUNT(*) FROM ${f}\G"|sed '/:/!d; s/^[^:]*: //g'`;
   [[ $c == 0 ]] && { echo "DROP db.$f" && mysql -e "use $db;DROP TABLE $f"; }
done

使用 PHP 的另一种方法是:

#connect to database first

$sql = "SHOW TABLE STATUS FROM `".$database."` 
WHERE ENGINE IS NOT NULL
AND `Rows`=0";
if($res = mysql_query($sql)){
    if(mysql_numrows($res)){
        while($r = mysql_fetch_assoc($res)){
            $table = $r['Name'];
            echo '<br />'.$table;
            if($ret = mysql_query("DROP TABLE `".$table."`")){
                echo ' = DROPPED';
            }else{
                echo ' = '.mysql_error();
            }
        }
    }
}

这将删除另一个执行,以确定该表没有行。

我在使用存储过程时遇到了GROUP_CONCAT问题。 奇怪的是,有些表没有被识别,它们似乎没有被找到。

我不熟悉存储过程。 因此我选择避免它们。 最后我用Python使用MySQL做了它,PHP非常相似:

import MySQLdb

conn = MySQLdb.connect(
    host='localhost',
    user='root',
    passwd='mypassword',
    db='mydatabase'
    )

c = conn.cursor()
c.execute('SHOW TABLES')
for table in c.fetchall():    
    c.execute('SELECT * FROM %s' % table[0])
    if c.rowcount == 0:
        c.execute('DROP TABLE %s' % table[0])

试试这个 :

  $tables = $conn->query('SHOW TABLES');
            $i = 0;
                while($table = $tables->fetch_array(MYSQLI_NUM)){
                    $table = $table[0];
                    $records =  $conn->query("SELECT * FROM `$table`");
                    if($records->num_rows == 0){
                        if ($conn->query(" DROP TABLE `$table` ")){
                           $i++;
                        }
                    }
                }
       return $i;

变量 $i 显示已删除表的计数

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM