简体   繁体   English

select语句中的动态表名

[英]dynamic table name in select statement

I have a series of history tables in an oracle 9 database. 我在oracle 9数据库中有一系列历史表。 History_table_00 contains last months data, History_table_01 contains the month before, and History_table_02 the month before that. History_table_00包含上个月的数据,History_table_01包含前一个月,History_table_02包含前一个月。 Next month, History_table_02 will automatically get renamed to history_table_03, history_table_01 renamed to history_table_02, history_table_00 renamed to history_table_01, and a new history_table_00 will be created to gather the newest history (I really hope I am making sense). 下个月,History_table_02将自动重命名为history_table_03,history_table_01重命名为history_table_02,history_table_00重命名为history_table_01,并且将创建新的history_table_00以收集最新的历史记录(我真的希望我有意义)。

Anyway, I need to write a select statement that will dynamically select all history tables. 无论如何,我需要编写一个select语句来动态选择所有历史表。 I am hoping this won't be too complicated because they all share the same name, just appended with sequential number so I can discover the table names with: 我希望这不会太复杂,因为它们都共享相同的名称,只是附加了序号,所以我可以发现表名:

select table_name from all_tables where table_name like 'HISTORY_TABLE_%';

My standard query for each table is going to be: 我对每个表的标准查询将是:

select id, name, data_column_1, data_column_2 from history_table_%;

What do I have to do to accomplish the goal of writing a sql statement that will always select from all history tables without me needing to go in every month and add the new table? 我需要做些什么来完成编写一个sql语句的目标,该语句总是从所有历史表中选择而不需要每个月都进入并添加新表? Thanks for anything you guys can provide. 感谢你们提供的任何东西。

you can use ref cursor but i wouldn't recommend it. 你可以使用ref游标,但我不推荐它。 it goes like this 它是这样的

create table tab_01 as select 1 a , 10 b from dual;
create table tab_02 as select 2 a , 20 b from dual;
create table tab_03 as select 3 a , 30 b from dual;

create or replace function get_all_history
return sys_refcursor
as
   r sys_refcursor;
   stmt varchar2(32000);
   cursor c_tables is
           select  table_name
           from    user_tables
           where   table_name like 'TAB_%';
begin
   for x in c_tables loop
           stmt := stmt || ' select * from ' || x.table_name ||' union all';
   end loop;
   stmt := substr(stmt , 1 , length(stmt) - length('union all'));
   open r for stmt;
   return r;
end;
/

SQL> select get_all_history() from dual;

GET_ALL_HISTORY()
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

         A          B
---------- ----------
         1         10
         2         20
         3         30

I would suggest you to define a view in which you select from all history tables using union all and each time the tables are renamed you modify the view as well. 我建议你定义一个视图,在这个视图中你可以使用union all从所有历史表中进行选择,每次重命名表时你也可以修改视图。

create OR replace view history_data as 
SELECT id, name, data_column_1, data_column_2  FROM history_table_01
union all 
SELECT id, name, data_column_1, data_column_2  FROM history_table_02
union all 
SELECT id, name, data_column_1, data_column_2  FROM history_table_03
;

then you can simle SELECT * FROM history_data; 然后你就可以看到SELECT * FROM history_data;

you can build the view dynamicaly with the help of the following statment: 您可以借助以下参数动态构建视图:

SELECT 'SELECT id, name, data_column_1, data_column_2  FROM ' || table_name || ' union all ' 
FROM  user_tables 
WHERE table_name like 'HISTORY_TABLE_%'     

The best idea is to do a dynamic SQL statement that builds up a large query for each table existing in the database. 最好的想法是执行动态SQL语句,为数据库中现有的每个表构建一个大型查询。 Give the following SQL query try. 尝试以下SQL查询。 (please forgive my formatting, I am not sure how to do line-breaks on here) (请原谅我的格式,我不知道如何在此处进行换行)

DECLARE @table VARCHAR(255)
      , @objectID INT
      , @selectQuery VARCHAR(MAX)

SELECT @objectID = MIN(object_id)
  FROM sys.tables
 WHERE name LIKE 'history_table_%'

WHILE @objectID IS NOT NULL
BEGIN
  SELECT @table = name
    FROM sys.tables
   WHERE object_id = @objectID
   ORDER BY object_id

  SELECT @selectQuery = ISNULL(@selectQuery + ' UNION ALL ', '') + 'select id, name, data_column_1, data_column_2 FROM ' + @table

  SELECT @objectID = MIN(object_id)
    FROM sys.tables
   WHERE name LIKE 'tblt%'
     AND object_id > @objectID
END 

SELECT @selectQuery
--EXEC (@selectQuery)

A Possible Solution: 可能的解决方案:

    CREATE OR REPLACE PROCEDURE GET_HIST_DETAILS IS

DECLARE

QUERY_STATEMENT VARCHAR2(4000) := NULL;
CNT             NUMBER;

BEGIN 

select COUNT(table_name) INTO CNT from all_tables where table_name like 'HISTORY_TABLE_%';

FOR loop_counter IN 1..CNT

LOOP

 IF LOOP_COUNTER <> CNT THEN
 {  
 QUERY_STATEMENT := QUERY_STATEMENT || 'select id, name, data_column_1, data_column_2 from history_table_0' || loop_counter || ' UNION';
 }
 ELSE
 {
   QUERY_STATEMENT := QUERY_STATEMENT || 'select id, name, data_column_1, data_column_2 from history_table_0' || loop_counter ;
 } 

EXECUTE_IMMEDIATE QUERY_STATEMENT;

END LOOP;


END GET_DETAILS;

PS:I dont have Oracle installed , so havent tested it for syntax errors. PS:我没有安装Oracle,所以没有测试它的语法错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM