mysql - 创建动态联合

时间:2018-04-19 14:01:55

标签: mysql dynamic union

数据库是mysql / mariaDB。

我的数据库旨在存储有关某事的月度报告。他们的名字是(例子):table1,table2,table3 ......

我想创建将创建/重新创建包含所有表union(union ALL)的视图的函数/过程。

类似的东西:
1.首先从信息模式中选择所有表名。

SELECT TABLE_NAME from information_schema.`TABLES` where TABLE_NAME like 'table%'  
  1. 然后我会尝试在某个循环中设置它以使用第一个查询的结果集。
  2. 但我在第一步遇到问题,我尝试仅合并一个固定表+第一个查询中的一个,并向我返回错误。

    我试试:

    select * from `table4`
    UNION
    SELECT * from (SELECT TABLE_NAME from information_schema.`TABLES`
        where TABLE_NAME like 'table%' limit 1) as dd
    

    它返回错误:使用的SELECT语句具有不同数量的列, 但是当我执行子查询时,我得到1个具有正确表名的结果,并且当我在没有子查询的from子句中设置该名称时,它可以工作。

    知道它为什么会发生,也许还有一些建议如何实现这种动态联合。

1 个答案:

答案 0 :(得分:1)

我认为有点推动可以帮助您正确处理这个问题。

首先,正如Tim Biegeleisen所说,继续的方法是使用动态SQL,如果在尝试运行查询之前无法绝对确定表名,这是唯一的途径。

其次,你认为你需要从查询information_schema.TABLE开始是正确的,你应该使用CURSOR来做。然后应该使用该查询的结果来构建一个查询字符串,然后使用PREPARE和EXECUTE。

第三,我认为您在帖子中包含的错误消息特指运行该查询,并不表示每月表格有任何不同。除非每个部分的结果返回相同数量的列,否则您无法执行UNION。

第四,因为我们要动态构建查询,这必须在存储过程中完成,所以无法在存储函数中完成。

有关使用CURSORPREPARE/EXECUTE的mysql文档中有很好的教程,您应该阅读这些教程。我在下面给出的版本将基于这些示例。我假设唯一的输入参数是模式名称(如果您碰巧在服务器上的另一个数据库中有一些类似命名的表)。

DELIMITER //

DROP PROCEDURE IF EXISTS dyn_union //
CREATE PROCEDURE dyn_union(IN v_sname VARCHAR(64))
READS SQL DATA
BEGIN
  -- NB the order of declaration for variables cursor 
  -- and handler must be strictly observed

  DECLARE sname VARCHAR(64);      -- variable the schema names  
  DECLARE tname VARCHAR(64);      -- variable the table names  

  DECLARE done INT DEFAULT FALSE; -- cursor control variable
  DECLARE cur1 CURSOR FOR 
    SELECT table_schema, table_name 
    FROM information_schema.TABLES
    WHERE table_schema = v_sname 
    AND table_name LIKE 'table%';

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  SET @sql = '';  -- build the query string in this var

  OPEN cur1;

  read_loop: LOOP                 -- loop over the rows returned by cursor
    FETCH cur1 INTO sname, tname; -- fetching the schema and table names
    IF done THEN
      LEAVE read_loop;
    END IF;

    IF @sql = '' THEN  -- build the select statement  
      SET @sql := CONCAT('SELECT * FROM `', sname, '`.`', tname, '`');
    ELSE
      SET @sql := CONCAT(@sql, ' UNION ALL SELECT * FROM `', sname, '`.`', tname, '`');
    END IF;
  END LOOP;

  CLOSE cur1;

select @sql;

  PREPARE stmt FROM @sql;  -- prepare and execute the dynamically
  EXECUTE stmt;            -- created query.
  DEALLOCATE PREPARE stmt;  

END //

DELIMITER ;

-- call the procedure
CALL dyn_union('your_db_name');