我试图编写MySQL脚本,删除按模式选择的一些表,但我的程序没有编译。请问有人可以提出问题吗?
delimiter #
drop procedure if exists drop_audit_tables #
create procedure drop_audit_tables()
begin
declare done int default false;
declare cmd varchar(4000);
declare cmds cursor for select 'drop table [' + table_name + ']' from information_schema.tables where table_name like '%_audit';
declare continue handler for not found set done = true;
open cmds;
tLoop: loop
fetch cmds into cmd;
if done then
leave tLoop;
end if;
PREPARE STMT FROM cmd;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
end loop tLoop;
close cmds;
end #
错误消息:
[42000] [1064]您的SQL语法有错误;检查与您的MySQL服务器版本对应的手册,以便在
答案 0 :(得分:0)
你的专栏:
declare cmds cursor for select 'drop table [' + table_name + ']' from information_schema.tables where table_name like '%_audit';
..使用table_name
而不先定义它。
首先尝试使用以下内容进行定义:
create procedure drop_audit_tables(IN table_name VARCHAR(64))
您可能需要考虑直接从存储过程获取变量并将其放入ad-hoc查询中的安全隐患。
仍然,在某处定义table_name
。在这种情况下,table_name
将作为参数提供给存储过程。然后,您的任务是收集一组表名,并在for / foreach循环中运行此代码。
/* Get the audit tables. */
$stmt = $pdo->query(`CALL get_audit_tables()`)
$tables = $stmt->fetch();
$stmt->close()
$stmt = $pdo->prepare('CALL drop_audit_tables(:table)')
/* Drop each audit table. */
foreach($tables as $table)
{
$stmt->bindParam(:table, $table, PDO::PARAM_STR)
$stmt->execute();
}
$stmt->close();
无论如何都是这样的。
将参数指定为IN,OUT或INOUT仅对PROCEDURE有效。对于FUNCTION,参数始终被视为IN参数。
准备由PDOStatement :: execute()方法执行的SQL语句。 SQL语句可以包含零个或多个命名(:name)或问号(?)参数标记,在执行语句时将替换实际值。
这样的解决方案会让您的生活更轻松。您只需定义一个查找审计表的基本查询。更少的代码。简单。
答案 1 :(得分:0)
您可以避开光标:
mysql> DROP TABLE IF EXISTS `one_audit`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `two_audit`;
Query OK, 0 rows affected (0.01 sec)
mysql> DROP TABLE IF EXISTS `three_audit`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `one_audit`(`a` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `two_audit`(`a` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `three_audit`(`a` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> SET @`drop_tables` := (
-> SELECT
-> CONCAT('DROP TABLE IF EXISTS ',
-> GROUP_CONCAT(CONCAT('`', `TABLE_NAME`, '`') SEPARATOR ', '))
-> FROM
-> `information_schema`.`TABLES`
-> WHERE
-> `TABLE_SCHEMA` = DATABASE() AND
-> `TABLE_TYPE` = 'BASE TABLE' AND
-> `TABLE_NAME` LIKE '%_audit'
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @`drop_tables`;
+--------------------------------------------------------------+
| @`drop_tables` |
+--------------------------------------------------------------+
| DROP TABLE IF EXISTS `one_audit`, `three_audit`, `two_audit` |
+--------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> PREPARE `exec` FROM @`drop_tables`;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE `exec`;
Query OK, 0 rows affected (0.00 sec)
mysql> DEALLOCATE PREPARE `exec`;
Query OK, 0 rows affected (0.00 sec)
您必须小心系统变量group_concat_max_len。
<强>更新强>
使用游标:
DELIMITER #
DROP PROCEDURE IF EXISTS `drop_audit_tables`#
CREATE PROCEDURE `drop_audit_tables`()
BEGIN
DECLARE `done` BOOL DEFAULT 0;
DECLARE `cmd` VARCHAR(4000);
DECLARE `cmds` CURSOR FOR
SELECT
CONCAT('DROP TABLE IF EXISTS `', `TABLE_NAME`, '`')
FROM
`information_schema`.`TABLES`
WHERE
`TABLE_SCHEMA` = DATABASE() AND
`TABLE_TYPE` = 'BASE TABLE' AND
`TABLE_NAME` LIKE '%_audit';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET `done` := 1;
OPEN `cmds`;
`tLoop`: LOOP
FETCH `cmds` INTO `cmd`;
IF `done` THEN
CLOSE `cmds`;
LEAVE `tLoop`;
END IF;
SET @`cmd` := `cmd`;
PREPARE `STMT` FROM @`cmd`;
EXECUTE `STMT`;
DEALLOCATE PREPARE `STMT`;
END LOOP `tLoop`;
SET @`cmd` := NULL;
END#
CALL `drop_audit_tables`#
DELIMITER ;
PREPARE stmt_name FROM preparable_stmt
...
preparable_stmt 是字符串文字或用户变量 包含SQL语句的文本。
...