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

How to run the same query against multiple tables in the database

虽然 运行 查询 MYSQL 抱怨:Table '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$$

SELECT 语句的 FROM 部分必须有实际的 table 名称,而不是包含 table 名称的 CHAR(100) 变量.就是这样不行。

您似乎想 运行 针对数据库中具有相似结构的许多 table 进行特定查询。通常这意味着可以改进数据库模式。但是,如果你必须处理你拥有的东西,你将不得不使用 dynamic SQL。 link 到 MySQL 文档有一个示例 "that demonstrates how to choose the table on which to perform a query at runtime, by storing the name of the table as a user variable",这正是您所需要的。

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

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

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

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

这是关于 MySQL 动态 SQL How To have Dynamic SQL in MySQL Stored Procedure 的另一个 SO 问题的 link 以及一些示例。

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

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$$

另一种变体,如果您需要处理的 table 的数量不多,是动态构建一个大的 SQL 语句,其中包含您的所有 table循环,然后 EXECUTE 一气呵成:

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

我 运行 有时也参与其中,并且我使用了一个非常简单的技巧。我只是这样做(需要 Excel 或 Google 表格 [警告:我没有使用 Google 表格测试此过程]:

  1. 运行 SELECT table_name FROM information_schema.tables where table_schema='your_database_name' 获取 table 列表 (MySQL).
  2. 打开一个新的跨页sheet并将table列表复制到sheet的第"A"列,从第1行开始。
  3. 首先在单个 table 中测试您的查询,然后在准备就绪后,将查询复制到列 "B" 第 1 行。对于 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. Select 单元格 B1 并向下填充字符串公式以匹配 table 个名称的数量。
  5. 您不应该有每个 table 的查询列表。 Select 整个列 B 和 Copy-n-Paste 进入一个新的 SQL 执行 window(确保您的目标数据库设置为默认模式是安全的)。
  6. 如果您在粘贴时看到双引号 ",则必须将其删除。如果在 MySQL Workbench 中,只需按 Ctrl+H 并将所有 " 替换为空(将第二个框留空)。

这实际上很有效,因为在大多数情况下,公式中的双引号不会与 SQL 文本冲突。此外,我将这些行连接为字符串,但您可以改为尝试将每一行作为单独的行放在单独的 sheet 上,并使用公式来连接这种方式。我相信有创造力的人可以找到其他类似的方法。

当然,这个想法只要稍作调整就适用于任何数据库,所以这是一个优点。 ;)