MySQL 版本 5.5.37:使用 CURSOR 删除超过 30 天的表

Posted

技术标签:

【中文标题】MySQL 版本 5.5.37:使用 CURSOR 删除超过 30 天的表【英文标题】:MySQL Version 5.5.37: Dropping tables older than 30 days using CURSOR 【发布时间】:2014-04-11 11:26:54 【问题描述】:

我一直在研究试图找到一种从查询结果中获取所有行并单独处理它们的方法。我写了一个脚本,我认为它可以工作,但显然不行。

脚本:

DECLARE @name char(20);

DECLARE c1 CURSOR READ_ONLY
FOR
SELECT table_name
FROM information_schema.tables WHERE table_schema = 'puslogger' AND UPDATE_TIME < (now() - interval 30 day)

OPEN c1; 

FETCH NEXT FROM c1
INTO @table_name

WHILE @@FETCH_STATUS = 0
BEGIN

PREPARE stmt FROM "concat('DROP TABLE IF EXISTS `', @table_name,'`;')"
EXECUTE stmt
DEALLOCTATE stmt

FETCH NEXT FROM c1
INTO @table_name

END

CLOSE c1
DEALLOCATE c1

该脚本旨在删除所有超过 30 天的表。虽然它似乎不适用于 mysql 版本 5.5.37。

我是 MySQL 新手,我正在使用 MySQL for Windows (XP) 运行服务器。也许 CURSORS 的这种语法对于相应的服务器版本不正确?我不确定,但如果有人可以帮助我,我会非常高兴。

编辑:

这是我尝试从 SQL 命令行执行脚本时返回的错误消息:

ERROR 1064 (42000):您的 SQL 语法有错误;

查看与您的 MySQL 服务器版本相对应的手册,了解在第 1 行的“DECLARE @name char(20)”附近使用的正确语法

ERROR 1064 (42000):您的 SQL 语法有错误;

查看与您的 MySQL 服务器版本相对应的手册,了解在附近使用的正确语法 'DECLARE c1 CURSOR READ_ONLY 为了 选择表名 FROM information_schema.tables' 第 1 行

ERROR 1064 (42000):您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以获取在附近使用的正确语法 '拿来 下一个来自 c1 INTO @table_name

WHILE @@FETCH_STATUS = 0 开始

PREPARE st' 在第 1 行

更新:

我也尝试了这个脚本(注意:我打算创建一个每天执行的事件以删除超过 30 天的表。):

delimiter |

CREATE EVENT clean_logger
    ON SCHEDULE EVERY 1 DAY
    DO
    BEGIN
        DECLARE @name char(20);
    DECLARE c1 CURSOR READ_ONLY
    FOR
    SELECT table_name
    FROM information_schema.tables WHERE table_schema = 'puslogger' AND UPDATE_TIME < (now() - interval 30 day);

    OPEN c1; 

    FETCH NEXT FROM c1
    INTO @table_name;

    WHILE @@FETCH_STATUS = 0
    BEGIN

    PREPARE stmt FROM "concat('DROP TABLE IF EXISTS `', @table_name,'`;')";
    EXECUTE stmt;
    DEALLOCTATE stmt;

    FETCH NEXT FROM c1
    INTO @table_name;

    END;

CLOSE c1;
DEALLOCATE c1;
END |

delimiter ;

在 SQL 命令行中运行此脚本返回:

ERROR 1064 (42000):您的 SQL 语法有错误;

查看与您的 MySQL 服务器版本相对应的手册,了解在附近使用的正确语法 '@name 字符(20); 声明 c1 CURSOR READ_ONLY 为了 选择表名 FROM infor' 在第 5 行

【问题讨论】:

您的代码中缺少语句分隔符 (;),您是否在发布之前将其剥离,或者您的原始代码中是否真的缺少它们?此外,DECLARE 只能在存储过程/函数中工作,为了简洁起见,您是否还剥离了函数/过程标头? 除了@RandomSeed 的要点之外,您还需要定义“似乎不起作用”的含义。您遇到什么错误或行为? 不,我发布了整个脚本。我将它保存为 sql 文件并从 SQL 命令行执行。所以,是的,缺少语句分隔符。我不确定如何正确地将这个想法放入工作脚本中。 @dan1111 我添加了执行脚本返回的错误信息。 (见编辑) 【参考方案1】:

试试下面的步骤:

DELIMITER $$

USE `test`$$

DROP PROCEDURE IF EXISTS `sp_drop_table`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_drop_table`()
BEGIN
        DECLARE done INT(1) DEFAULT 0;
        DECLARE _tblname VARCHAR(20) DEFAULT '';

        DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = 'puslogger' AND UPDATE_TIME < (NOW() - INTERVAL 30 DAY);
        DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
-- open cursor1
OPEN cur1;
BEGIN

REPEAT
FETCH cur1 INTO _tblname;
IF _tblname = '' THEN
    SET done = 1;
END IF; 

            IF (done<>1) THEN
    SET @str1=CONCAT("DROP TABLE IF EXISTS ",_tblname);
                 PREPARE stmt1 FROM @str1;
                 EXECUTE stmt1;
                 DEALLOCATE PREPARE stmt1;

            END IF;

UNTIL done
END REPEAT;
END;
     CLOSE cur1;
-- close cursor1     

     SELECT 'done';

END$$

DELIMITER ;

【讨论】:

非常感谢,我一定会试试这个,如果成功,我会接受这个作为最佳答案:) 太棒了,我只需将SET @str1=CONCAT("DROP TABLE IF EXISTS ",_tblname); 更改为SET @str1=CONCAT("DROP TABLE IF EXISTS `",_tblname,"`"); 再次感谢您。

以上是关于MySQL 版本 5.5.37:使用 CURSOR 删除超过 30 天的表的主要内容,如果未能解决你的问题,请参考以下文章

Freebsd10.3 Nginx多版本PHP

安装mysql二进制版

MySQL通过游标(CURSOR)实现对select选择集的迭代使用,解决在Navicat中声明游标就一直报错的问题

python3版本mysql的操作

python获取mysql返回内容

MySQL游标(cursor) 定义及使用