如何对数据库中的多个表运行相同的查询

时间:2015-03-25 01:07:28

标签: mysql sql database procedure

在运行以下查询MYSQL时抱怨:表'DB.tableName'不存在。

CREATE PROCEDURE CountSignatures()
  BEGIN
     DECLARE done INT DEFAULT FALSE;
     DECLARE signatureCount INT;
     DECLARE tableName CHAR(100);
     DECLARE tableList CURSOR FOR Select table_name from information_schema.tables where table_name like "%FAULT_20150320%";
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
     SET signatureCount = 1;
     OPEN tableList;
     tableListLoop: LOOP
       SET done = FALSE ;
       FETCH tableList INTO tableName;
       IF done THEN
         LEAVE tableListLoop;
       END IF;

     **Select count(distinct signature) from tableName;**

     END LOOP;
     CLOSE tableList;
  END$$

如果我使用以下查询,则正确打印tableName变量值:

CREATE PROCEDURE CountSignatures()
  BEGIN
     DECLARE done INT DEFAULT FALSE;
     DECLARE signatureCount INT;
     DECLARE tableName CHAR(100);
     DECLARE tableList CURSOR FOR Select table_name from information_schema.tables where table_schema="LogData" and table_name like "%FAULT_20150320%";
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
     SET signatureCount = 1;
     OPEN tableList;
     tableListLoop: LOOP
       SET done = FALSE ;
       FETCH tableList INTO tableName;
       IF done THEN
         LEAVE tableListLoop;
       END IF;

       **Select tableName;**

     END LOOP;
     CLOSE tableList;
  END$$

2 个答案:

答案 0 :(得分:0)

FROM语句的SELECT部分必须包含实际的表名,而不是包含表名的CHAR(100)变量。它不会像这样工作。

看起来您希望针对数据库中具有类似结构的许多表运行特定查询。通常,这意味着可以改进数据库模式。但是,如果你必须处理你拥有的东西,你将不得不使用dynamic SQL。这个指向MySQL文档的链接有一个示例"它演示了如何选择在运行时执行查询的表,方法是将表的名称存储为用户变量",这正是您所需要的。

在循环内部,您需要使用SQL查询构建一个字符串并使用EXECUTE

SET @s = CONCAT('select count(distinct signature) from ', tableName);

PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

据我所知,EXECUTE的结果被发送给存储过程的调用者,就像它是正常的SELECT一样,所以在这个例子中,调用者将收到多个结果集如果您的数据库有多个表where table_name like "%FAULT_20150320%"

以下是关于MySQL动态SQL How To have Dynamic SQL in MySQL Stored Procedure的另一个SO问题的链接,其中包含一些示例。

看起来你想要这样的东西。它应该总结signatureCount变量中的几个表的计数。

CREATE PROCEDURE CountSignatures()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE signatureCount INT;
    DECLARE tableName CHAR(100);
    DECLARE tableList CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_name LIKE "%FAULT_20150320%";
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    SET signatureCount = 0;
    OPEN tableList;
    tableListLoop: LOOP
        SET done = FALSE;
        FETCH tableList INTO tableName;
        IF done THEN
            LEAVE tableListLoop;
        END IF;

        SET @VarCount = 0;
        SET @VarSQL = CONCAT('SET @VarCount = (SELECT COUNT(DISTINCT signature) FROM ', tableName, ')');

        PREPARE stmt FROM @VarSQL;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;

        SET signatureCount = signatureCount + @VarCount;
    END LOOP;
    CLOSE tableList;

    SELECT signatureCount;
END$$

另一个变体,如果你需要处理的表的数量不多,那就是动态构建一个包含循环内所有表的大SQL语句,然后一次性EXECUTE

SELECT 
(COUNT(DISTINCT signature) FROM Table1) +
(COUNT(DISTINCT signature) FROM Table2) +
...
(COUNT(DISTINCT signature) FROM TableN) AS TotalCount

答案 1 :(得分:0)

我有时也碰到这个,并且使用了一个非常简单的技巧。我这样做(需要Excel或Google表格[警告:我没有使用Google表格测试过程]):

  1. 运行SELECT table_name FROM information_schema.tables where table_schema='your_database_name'以获取表格列表(MySQL)。
  2. 打开一个新的电子表格并将表格列表复制到" A"从第1行开始的工作表。
  3. 首先在一个表中测试您的查询,然后在准备好后,将查询复制到列" B"对于MS Excel,有一个字符串限制,所以你需要连接字符串(我只是逐行):

    ="ALTER TABLE `mydatabasename`.`"&A1&"`
    "&"CHANGE COLUMN `created` `created` DATETIME NOT NULL COMMENT 'Comment here...' ,
    "&"CHANGE COLUMN `updated` `updated` DATETIME NOT NULL COMMENT 'Comment here...' ;"&
    "&"...etc...
    "&"...etc...
    "&"...etc...
    "
    

    开头的"&"需要从上一行捕获新的行字符。

  4. 选择单元格B1并向下填充字符串公式以匹配表名称数。
  5. 您不应该为每个表都有一个查询列表。选择整个列B和Copy-n-Paste到一个新的SQL执行窗口(确保将目标数据库设置为安全的默认模式)。
  6. 如果您在粘贴时看到双引号",则必须将其删除。如果在MySQL Workbench中只需按Ctrl + H并将所有"替换为空(将第二个框留空)。
  7. 这实际上很有效,因为公式中的双引号在大多数情况下与SQL文本不会发生冲突。此外,我将这些行连接为字符串,但您可以将每一行作为单独的工作表上的单独行进行尝试,并使用公式来连接这种方式。我确信有创意的人可以找到其他类似的方式。

    当然,这个想法适用于任何带有微小调整的数据库,因此这是一个优点。 ;)