【问题标题】:Truncate all tables in MySQL database that match a name pattern截断 MySQL 数据库中与名称模式匹配的所有表
【发布时间】:2009-10-15 22:11:24
【问题描述】:

我需要清空我所有的库存表。

我试过了:

SELECT 'TRUNCATE TABLE ' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'inventory%'

但我收到此错误:

Truncated incorrect DOUBLE value: 'TRUNCATE TABLE ' Error Code 1292

如果这是正确的方法,那我做错了什么?

【问题讨论】:

  • 您意识到不会运行截断语句,只需将它们创建为结果集中的字符串?
  • + 语法对 MySQL 无效。你必须使用 concat 函数。

标签: sql mysql


【解决方案1】:

使用连接:

SELECT concat('TRUNCATE TABLE `', TABLE_NAME, '`;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'inventory%'

这当然只会生成您需要自己复制和运行的 SQL。

【讨论】:

  • 好的,所以我复制了结果,将其粘贴到查询浏览器中,按 CtrlEnter 和 boooom!!!!什么也没发生,表中还有数据 =(
  • 看来我必须在查询浏览器中执行每一行,至少我不必写所有行,只需在每一行上按 CtrlEnter o.O
  • 必须是你的mysql客户端的一个功能。 ';'应该在大多数客户端中用作语句分隔符
  • 您可能还想添加AND TABLE_SCHEMA = 'mydatabase' 以确保您只在特定数据库上进行操作。此外,添加INTO OUTFILE 'c:\\script.sql' 将避免您复制和粘贴任何内容;相反,只需运行脚本。
  • 将整个查询放在 1 行的小技巧:SELECT group_concat(a.c SEPARATOR ' ') FROM (SELECT concat('TRUNCATE TABLE ', TABLE_NAME, ';') AS c FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'inventory%') a;
【解决方案2】:

试试这个语句,它会给你所有表的单行,你可以复制这些语句并运行以执行所有:

SELECT DISTINCT REPLACE(GROUP_CONCAT("TRUNCATE TABLE ", TABLE_NAME, ";"), ',', '')
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME LIKE "cache%";

【讨论】:

  • 我喜欢这个主意。但是 mysql 客户端正在修剪结果,所以它被切断了。有人知道如何防止它这样做吗?
  • 查询无法正常工作。它返回像“cache_SOMETHING”这样的表名,其中 SOMETHING 是一个表,但 cache_SOMETHING 不是。
  • GROUP_CONCAT 替换为仅CONCAT 函数,它将为您提供每一行中的每个TRUNCATE TABLE TABLE_NAME;,然后您可以复制每一行并按预期运行它。因此,现在您的 MySQL 客户端不会修剪结果。
【解决方案3】:

这里对上面的SQL语句做了一点改进。

SELECT DISTINCT concat("TRUNCATE TABLE ", TABLE_NAME, ";") 
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME LIKE "cache%"

注意开头的 DISTINCT 命令。这将使 SELECT 结果只显示一次与您的 LIKE 条件匹配的表。

【讨论】:

  • 您是否从服务器上的多个数据库访问表?
【解决方案4】:

我知道这是一篇较旧的帖子,但也许下面的示例对需要从 linux 命令行或 shell 脚本中截断多个表的人有所帮助:

mysql -p<secret> --execute="SELECT concat('TRUNCATE TABLE ', TABLE_NAME, ';') FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '<database>' AND FIND_IN_SET(TABLE_NAME,'your_table_a,your_table_b,your_table_c')" | sed 1d | mysql -p<secret> <database>

鉴于您需要用自己的值替换括号中的字符串,这对我有用。还将 'your_table_a,your_table_b,your_table_c' 替换为以逗号分隔的表格列表。 ;)

【讨论】:

  • 如果您碰巧需要刷新所有缓存表,因为您设置了像 memcache 这样的解决方案,这里有一个有用的命令: mysql -uroot -proot --execute="SELECT concat('TRUNCATE TABLE ', TABLE_NAME , ';') 从 INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'db_name' AND TABLE_NAME LIKE 'cache%'" | sed 1d | mysql -uroot -proot db_name ... 只需更新 db_name 和用户凭据。
【解决方案5】:

我刚刚读到的使用 concat 生成和执行语句的非常好的示例:

http://www.mysqltutorial.org/mysql-drop-table

-- set table schema and pattern matching for tables

SET @schema = 'classicmodels';
SET @pattern = 'test%';

-- build dynamic sql (DROP TABLE tbl1, tbl2...;)

SELECT CONCAT('DROP TABLE ',GROUP_CONCAT(CONCAT(@schema,'.',table_name)),';')
INTO @droplike FROM information_schema.tables WHERE @schema = database()
AND table_name LIKE @pattern;

-- display the dynamic sql statement

SELECT @droplike;  

-- execute dynamic sql

PREPARE stmt FROM @dropcmd;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

【讨论】:

  • 根据:stackoverflow.com/questions/20371677/…,不可能在一个准备好的语句中运行多个语句
  • 上述脚本适用于DROP TABLE,因为它可以接受多个表名。 TRUNCATE 并非如此。
【解决方案6】:
SELECT 'SET FOREIGN_KEY_CHECKS = 0;'
UNION
SELECT DISTINCT concat( "TRUNCATE TABLE ", TABLE_NAME, ";" )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'mydbname'
UNION
SELECT 'SET FOREIGN_KEY_CHECKS = 1;'

【讨论】:

  • 这个答案也会生成一串用 ; 分隔的 SQL 语句但这里的关键是它会在截断之前为您打开 foreign_key 检查,然后再次打开检查。如果您的表具有彼此指向的外键,则需要这样做。如果你在一个表中有一行带有外键到你截断的表,你会破坏引用并且 mysql 会抛出一个错误。
【解决方案7】:

如果您使用的是命令行,您可能想尝试这样的操作。

mysql -u [user] -p[password] -e 'use [database]; show tables' | perl -lane 'print "truncate table $F[0]" if /^inventory/i' > [database].sql

【讨论】:

    【解决方案8】:

    如果您的服务器上有多个数据库,您可能还需要指定数据库。

    例如清除 Drupal 缓存表

    SELECT DISTINCT CONCAT(  
        "TRUNCATE TABLE ", 
        TABLE_SCHEMA,  
        ".",
        TABLE_NAME, 
        ";" ) 
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_NAME LIKE  "cache_%"
    AND TABLE_SCHEMA = 'dbname';
    

    这会导致类似 sql...

    TRUNCATE TABLE dbname.cache_admin_menu;
    TRUNCATE TABLE dbname.cache_block;
    etc.
    

    有两个好处,

    1. 您可以在任何地方运行此 sql,而不管当前选择的是什么 数据库。
    2. 您肯定会截断 正确的数据库。

    如果外键检查妨碍您的批量截断,请参阅@falperez 答案,(当然它们不会用于清除 drupal 缓存)

    【讨论】:

      【解决方案9】:
      SELECT CONCAT('TRUNCATE TABLE ',TABLE_NAME)
      FROM INFORMATION_SCHEMA.TABLES
      WHERE TABLE_NAME LIKE 'inventory%'
      

      然后您应该获取结果集的每一行并将其作为 SQL 语句调用。您可以通过将分离的结果复制并粘贴到命令窗口来做到这一点。

      但是更好的解决方案是编写一些程序来进行上述查询并循环遍历结果并进行每个查询。

      使用 PHP 或任何其他脚本语言。甚至在 SO 上也有很多例子。

      【讨论】:

        【解决方案10】:
        SELECT REPLACE(GROUP_CONCAT("TRUNCATE TABLE ", TABLE_NAME, ";"), ',', '') 
        FROM INFORMATION_SCHEMA.TABLES 
        WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME LIKE "cache%";
        

        这是基于 AshwinP 的回答。我必须删除 DISTINCT 并添加 WHERE TABLE_SCHEMA=DATABASE() 才能为我工作。

        该命令不会截断表,但会返回一个单行。将单行复制粘贴到mysql客户端中。

        【讨论】:

          【解决方案11】:

          迟到的答案……但迟到总比没有好。为了避免不必要的复制和粘贴或额外的 shell 脚本,最不可知的方法——至少对于 MySQL 和 MariaDB——截断数据库中的一组表或匹配模式是通过存储过程。

          以下是一个经常用于截断当前数据库中所有表的脚本。如果需要更精确的控制,可以定制 SELECT 语句以匹配模式。

          DROP PROCEDURE IF EXISTS truncate_tables;
          
          DELIMITER $$
          CREATE PROCEDURE truncate_tables()
          BEGIN
            DECLARE tblName CHAR(64);
            DECLARE done INT DEFAULT FALSE;
            DECLARE dbTables CURSOR FOR
              SELECT table_name
              FROM information_schema.tables
              WHERE table_schema = (SELECT DATABASE());
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
          
            OPEN dbTables;
            SET FOREIGN_KEY_CHECKS = 0;
          
            read_loop: LOOP
              FETCH dbTables INTO tblName;
              IF done THEN
                LEAVE read_loop;
              END IF;
          
              PREPARE stmt FROM CONCAT('TRUNCATE ', tblName);
              EXECUTE stmt;
              DEALLOCATE PREPARE stmt;
            END LOOP read_loop;
          
            CLOSE dbTables;
            SET FOREIGN_KEY_CHECKS = 1;
          END
          $$
          
          CALL truncate_tables();
          DROP PROCEDURE IF EXISTS truncate_tables;
          

          此示例在使用存储过程后将其删除。但是,如果这是一项常规任务,那么最好只添加一次,方法是运行 $$ 分隔符之前的所有内容并执行

          CALL truncate_tables();
          

          在目标数据库上。

          【讨论】:

            【解决方案12】:
            mysql -uuser -ppass --execute="SELECT concat('TRUNCATE TABLE ', TABLE_NAME, ';') FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME LIKE 'cache%'" | sed 1d | mysql -uuser -ppass db 
            

            ..这对我有用.. 用您自己的替换 userpassdb

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-11-02
              • 2011-06-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-19
              • 2011-08-12
              相关资源
              最近更新 更多