dynamic table name in select statement

2019-03-05 23:41发布

问题:

I have a series of history tables in an oracle 9 database. History_table_00 contains last months data, History_table_01 contains the month before, and History_table_02 the month before that. 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).

Anyway, I need to write a select statement that will dynamically select all history tables. 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? Thanks for anything you guys can provide.

回答1:

you can use ref cursor but i wouldn't recommend it. 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


回答2:

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.

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;

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_%'     


回答3:

The best idea is to do a dynamic SQL statement that builds up a large query for each table existing in the database. Give the following SQL query try. (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)


回答4:

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.