mysql动态查询执行

时间:2016-04-14 15:00:53

标签: mysql database

我试图编写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服务器版本对应的手册,以便在

2 个答案:

答案 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循环中运行此代码。

基本(非健壮)PHP(PDO)

/* 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();

无论如何都是这样的。

  

MySQL: CREATE PROCEDURE

     

将参数指定为IN,OUT或INOUT仅对PROCEDURE有效。对于FUNCTION,参数始终被视为IN参数。

     

PHP Manual: PDO::prepare

     

准备由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 ;
  

14.5.1 PREPARE Syntax

     

PREPARE stmt_name FROM preparable_stmt

     

...

     

preparable_stmt 是字符串文字或用户变量   包含SQL语句的文本。

     

...