MySQL 在表名中使用通配符

Posted

技术标签:

【中文标题】MySQL 在表名中使用通配符【英文标题】:MySQL use a wild card in table name 【发布时间】:2020-09-25 19:24:07 【问题描述】:

所以我有一个软件可以在这些表上存储数据。我知道这些表是如何开始的,但它们总会有一个后缀,这是一个我不知道知道的数字 这些表名的例子是"itemid5_4423"

我知道有一个名为 itemid5 的表,但我无法知道后缀号 有没有类似这种逻辑的通配符select * from itemid5_*;

【问题讨论】:

不能在表名或字段名中使用通配符。您可以使用SHOW TABLES 了解数据库中的表。 您可以在存储过程中创建动态查询。遍历以 itemid5 开头的所有表,并创建一个查询,该查询将从每个表中提取数据。您是否正在寻找此类查询或过程的示例? 拥有多个“相同”的表通常是不好的做法,而且很笨拙。您已经找到了它笨拙的原因之一。 这两个答案对你有帮助吗,亚当? 【参考方案1】:

假设您有 2 个这样的表:

create table itemid5_1111 (id int, itemname varchar(100));
create table itemid5_2222 (id int, itemname varchar(100));

您将数据插入其中:

insert into itemid5_1111 values (1, 'first table');
insert into itemid5_2222 values (2, 'second table');

您的目标是从所有 itemid5* 表中获得这样的输出。

+------+--------------+
| id   | itemname     |
+------+--------------+
|    1 | first table  |
|    2 | second table |
+------+--------------+

您可以通过键入:

          select * from itemid5_1111
union all select * from itemid5_2222;

但是,这需要大量手动输入。可以做一个存储过程动态查询itemid5开头的表名,然后动态创建SQL并执行。

存储过程

delimiter $$

drop procedure if exists get_items$$

create procedure get_items()
begin

    declare eof boolean default false;
    declare mytable varchar(255);
    declare first_run boolean default true;

    declare tablenames_cursor cursor for
        select table_name from information_schema.tables
        where table_name like 'itemid%';

    declare continue handler for not found
        set eof = true;

    set @my_query = '';

    open tablenames_cursor;
    read_loop: loop

        fetch tablenames_cursor into mytable;
        if eof then
            leave read_loop;
        end if;

        if first_run then
            set @my_query = concat('select * from ', mytable);
            set first_run = false;
        else
            set @my_query = concat(@my_query, ' union all ', 'select * from ', mytable);
        end if;

    end loop;
    close tablenames_cursor;

    prepare stmt from @my_query;
    execute stmt;
    deallocate prepare stmt;

end$$

delimiter ;

你这样调用这个过程来得到你的结果:

call get_items();

如果您像这样创建了第三张表:

create table itemid5_3333 (id int, itemname varchar(100));
insert into itemid5_3333 values (3, 'third table');

然后,你调用 proc,你会得到

call get_items();
+------+--------------+
| id   | itemname     |
+------+--------------+
|    1 | first table  |
|    2 | second table |
|    3 | third table  |
+------+--------------+

【讨论】:

【参考方案2】:

我认为使用数据字典来检索结果会有所帮助,运行它。

select * from information_schema.tables where table_name like 'itemid5_% ';

您可以选择此查询输出的列,table_name 是您需要的列之一,就像我们在 where 子句中使用的一样。

【讨论】:

【参考方案3】:
SELECT
REPLACE
    (
        GROUP_CONCAT(
            CONCAT("SELECT * FROM ", `TABLE_NAME`)
        ),
        ",",
        " UNION ALL "
    )
INTO @sq
FROM
    information_schema.tables
WHERE
    `TABLE_SCHEMA` = "test";
USE
    test;
PREPARE
    stmt1
FROM
    @sq;
EXECUTE
    stmt1;

【讨论】:

所有模式表都应该具有相同的结构,这一点很重要。我没有提到,但我只是假设它是。根据您的要求更改sql。它是从许多表中收集数据的捷径。【参考方案4】:
DELIMITER //
CREATE PROCEDURE merge_tables(IN in_sname VARCHAR(64),IN in_tname VARCHAR(64))
READS SQL DATA
BEGIN
  DECLARE sname VARCHAR(64);   
  DECLARE tname VARCHAR(64);
  DECLARE cname VARCHAR(64);   
  DECLARE done INT DEFAULT FALSE; 
  DECLARE table_cur CURSOR FOR SELECT table_schema, table_name FROM 
    information_schema.TABLES WHERE table_schema = in_sname AND table_name LIKE 
    'table%';
  DECLARE column_cur CURSOR FOR SELECT `COLUMN_NAME` FROM 
    `INFORMATION_SCHEMA`.`COLUMNS` where table_schema = in_sname and table_name 
    = in_tname;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  -- build column list (Using the column list for table listed in second 
     parameter in PROC Call)
  SET @column = '';  
  OPEN column_cur;
  column_cur_loop: LOOP          
    FETCH column_cur INTO cname; 
    IF done THEN
      -- SET @column := CONCAT(@column, ') ');
       LEAVE column_cur_loop;
    END IF;
    IF @column = '' THEN    
      SET @column := CONCAT(@column,cname);
    ELSE
      SET @column := CONCAT(@column,',',cname);
    END IF;
  END LOOP;
  CLOSE column_cur;


  -- Build UNION Query for all table starting with table%)
  SET done = FALSE;
  SET @sql = '';  
  OPEN table_cur;
    table_list_loop: LOOP                 
        FETCH table_cur INTO sname, tname; 
        IF done THEN
          LEAVE table_list_loop;
        END IF;

        IF @sql = '' THEN    
          SET @sql := CONCAT('INSERT INTO MERGED_TABLE (', @column , ') SELECT 
          ', @column , ' FROM `', sname, '`.`', tname, '`');
        ELSE
          SET @sql := CONCAT(@sql, ' UNION ALL SELECT ' , @column , ' FROM `', 
          sname, '`.`', tname, '`');
        END IF;
      END LOOP;
      CLOSE table_cur;


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

END //

DELIMITER ;`    

调用 merge_tables(testdb,table1)


testdb 是表所在的架构名称 table1 是需要合并以获取列名的表之一 过程中的table%是所有需要合并的表的前缀。

【讨论】:

以上是关于MySQL 在表名中使用通配符的主要内容,如果未能解决你的问题,请参考以下文章

注入点在表名中

[MySQL] 用通配符进行过滤

BigQuery 提取昨天的数据,其中日期在表名中为 filename20181203

四、MySQL数据库之通配符

mysql 总结

SQL之toplike通配符inbetween