MySQL过程的语法问题

时间:2017-08-01 12:53:06

标签: mysql stored-procedures

我创建了这个可以在堆栈溢出时找到的过程。我希望从具有特定列的所有表中获取行,以获取特定值。 所以:

  • 获取包含
  • 列的所有表格
  • 从表格中获取列值为x

    的所有行
    @DELIMITER $$
    CREATE PROCEDURE db.selectStuff ()
    BEGIN
      DECLARE a varchar(100);
      DECLARE i CURSOR FOR SELECT DISTINCT TABLE_NAME from INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME="my_column_name";
      OPEN i;
      read_loop: LOOP
        FETCH i INTO crt_table;
        SELECT * FROM crt_table WHERE my_column_name=some_id;
      END LOOP read_loop;
      CLOSE i;
    END$$
    @DELIMITER;
    call selectStuff();
    

我收到了这个

DBVisualizer Pro 9.5.7

运行时

[Code: 1064, SQL State: 42000] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DECLARE i CURSOR FOR SELECT DISTINCT TABLE_NAME from INFORMATION_SCHEMA.COLUMNS ' at line 1

选择有效。

更新: 从下面的评论中我将代码更改为:

@DELIMITER $$
CREATE PROCEDURE selectStuff ()
BEGIN
  DECLARE s VARCHAR(300);
  DECLARE i CURSOR FOR SELECT CONCAT('SELECT * FROM ',c.TABLE_NAME,' where `my_column_name`=1') as s from INFORMATION_SCHEMA.COLUMNS c WHERE c.COLUMN_NAME="my_column_name";
  OPEN i;
  do_stuff: LOOP
    FETCH i INTO s;
    PREPARE run FROM s;
    EXECUTE run;
    DEALLOCATE PREPARE run;
  END LOOP do_stuff;
  CLOSE i;
END$$
@DELIMITER;

call selectStuff();

我收到同样的错误。

注意:正在运行

SELECT CONCAT('SELECT * FROM ',c.TABLE_NAME,' where `my_column_name`=1') as s from INFORMATION_SCHEMA.COLUMNS c WHERE c.COLUMN_NAME="my_column_name" 

实际上是否提供了能够满足我想要的正确SQL语句。

更新: 在dbForge Studio Express中运行它:

DELIMITER $
CREATE PROCEDURE selectStuff()
BEGIN
  DECLARE done TINYINT DEFAULT 0;
  DECLARE s VARCHAR (3000);
  DECLARE i CURSOR FOR SELECT CONCAT("SELECT * FROM ", c.TABLE_NAME, " where my_column_name=1") as QUERY from INFORMATION_SCHEMA.COLUMNS c WHERE c.COLUMN_NAME="my_column_name";
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  OPEN i;
  do_stuff: LOOP
    FETCH i INTO s;
    IF done = 1 THEN LEAVE do_stuff;
    END IF;
    PREPARE stmt FROM s;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END LOOP do_stuff;
  CLOSE i;
END$
DELIMITER;

#call selectStuff();

我得到了一些其他错误,但光标部分通过了。

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 's;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END LOOP do_stuff;

1 个答案:

答案 0 :(得分:0)

好的,回答我自己的问题。

感谢@Solarflare提供非常有用的链接。

通过回答here,我能够进入上述问题的最后一个更新。 似乎错误是由PREPARE语句无法引用局部变量引起的,如答案here

中所述
  

在存储程序上下文中准备的语句不能引用存储过程或函数参数或局部变量,因为它们在程序结束时超出范围并且将不可用是稍后在程序外执行的语句。作为解决方法,请转而使用用户定义的变量,它们也具有会话范围;

THUS ,最终代码为:

DELIMITER $
DROP PROCEDURE IF EXISTS myName;
CREATE PROCEDURE myName(IN id INT)
BEGIN
  DECLARE s VARCHAR(255);
  DECLARE cont TINYINT DEFAULT 1;
  DECLARE crs CURSOR FOR SELECT CONCAT("SELECT * FROM `", c.TABLE_NAME, "` where `my_column`=",id) as Q from INFORMATION_SCHEMA.COLUMNS c WHERE c.COLUMN_NAME="my_column";
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET cont=0;
  SET @sys_var = ''; 
  #THIS is where we declare a user defined variable to 
  #which we pass the actual string we want to execute as sql
  OPEN crs;
  WHILE cont=1 DO
    FETCH crs INTO s;
    SET @sys_var =s; 
    #SELECT @sys_var as ''; #this is just to test if the strings are correct
    PREPARE stmt FROM @sys_var;   
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END WHILE;
  CLOSE crs;
END$
DELIMITER;

请注意我仍然将光标移到varchar,但我还将变量sys_var设置为具有相同的值,然后再将其传递给PREPARE 我也改用WHILE DO,因为 其他原因。

注意:我还添加了一个参数,但它与问题无关。