Transposing Undefined Number of Rows to Columns - sql

I have a table that looks like the following:
Member, Contract_Start, Contract_End
1, 1/1/2011, 12/30/2011
1, 1/1/2012, 12/30/2012
1, 1/1/2013, 12/30/2013
2, 7/1/2012, 12/30/2012
2, 1/1/2013, 12/30/2013
Members could have as few as 1 contract and there is no upper limit on number of contracts.
I'd like to switch the table to look like below:
Member, Contract_Start1, Contract_End1, Contract_Start2, Contract_End2.....
1, 1/1/2011, 12/30/2011, 1/1/2012, 12/30/2012
2, 7/1/2012, 12/30/2012, 1/1/2013, 12/30/2013
Thanks for any help you can give.

I have used such solution and would advise not to go this path because maintenance/debugging of such dynamic sql becomes to hard over long time.
you can try the demo Here
IF object_id('Test_Transpose') IS NOT NULL
DROP TABLE Test_Transpose
GO
CREATE TABLE Test_Transpose
(
memberID INT NOT NULL
,csdate datetime2(2) NULL
,cedate datetime2(2) NULL
)
INSERT INTO Test_Transpose (memberid,csdate,cedate)
SELECT 1,'1/1/2001','1/1/2001'
UNION ALL SELECT 1,'1/2/2001','1/2/2001'
UNION ALL SELECT 1,'1/3/2001','1/2/2001'
UNION ALL SELECT 1,'1/4/2001','1/2/2001'
UNION ALL SELECT 1,'1/5/2001','1/2/2001'
UNION ALL SELECT 2,'1/2/2001','1/2/2001'
UNION ALL SELECT 2,'1/3/2001','1/3/2001'
UNION ALL SELECT 3,'1/2/2001','1/2/2001'
UNION ALL SELECT 3,'1/3/2001','1/3/2001'
UNION ALL SELECT 3,'1/4/2001','1/4/2001'
UNION ALL SELECT 4,'1/2/2001','1/2/2001'
DECLARE #SQL NVARCHAR(MAX)=''
,#Startdate_SelectColumnList NVARCHAR(MAX)=''
,#EndDate_SelectColumnList NVARCHAR(MAX)=''
,#Final_SelectColumnList NVARCHAR(MAX)=''
,#PivotINColumnList NVARCHAR(MAX)=''
,#MaxContractDateCount INT=1
SELECT TOP 1 #MaxContractDateCount = COUNT(1)
FROM Test_Transpose
GROUP BY memberid
ORDER BY COUNT(1) desc
WHILE #MaxContractDateCount > 0
BEGIN
SELECT #Startdate_SelectColumnList = N'['+CAST(#MaxContractDateCount AS sysname)+N'] AS '
+N'StartDate'+CAST(#MaxContractDateCount AS sysname)
+CASE WHEN #Startdate_SelectColumnList=N'' THEN N'' ELSE N',' END
+#Startdate_SelectColumnList
SELECT #Enddate_SelectColumnList = N'['+CAST(#MaxContractDateCount AS sysname)+N'] AS '
+N'EndDate'+CAST(#MaxContractDateCount AS sysname)
+CASE WHEN #Enddate_SelectColumnList=N'' THEN N'' ELSE N',' END
+#Enddate_SelectColumnList
SELECT #Final_SelectColumnList = N'StartDate'+CAST(#MaxContractDateCount AS sysname)+N','
+N'EndDate'+CAST(#MaxContractDateCount AS sysname)
+CASE WHEN #Final_SelectColumnList=N'' THEN N'' ELSE N',' END
+#Final_SelectColumnList
SELECT #PivotINColumnList = N'['+CAST(#MaxContractDateCount AS sysname)+N']'
+CASE WHEN #PivotINColumnList=N'' THEN N'' ELSE N',' END
+#PivotINColumnList
SET #MaxContractDateCount=#MaxContractDateCount-1
END
--debug stmt
--SELECT #Startdate_SelectColumnList,#Enddate_SelectColumnList,#Final_SelectColumnList,#PivotINColumnList
SET #SQL = N'
SELECT q1.memberid,'
+#Final_SelectColumnList
+N'
FROM
(
SELECT memberid,'
+#Startdate_SelectColumnList
+N'
FROM
(
SELECT memberid,csdate,ROW_NUMBER() OVER (PARTITION BY memberid ORDER BY memberid,csdate) rowid
FROM test_transpose
)q
PIVOT
(MAX(csdate) FOR rowid IN ('+#PivotINColumnList+N'))pvt
)q1
JOIN
(
SELECT memberid,'
+#Enddate_SelectColumnList
+N'
FROM
(
SELECT memberid,cedate,ROW_NUMBER() OVER (PARTITION BY memberid ORDER BY memberid,csdate) rowid
FROM test_transpose
)q
PIVOT
(MAX(cedate) FOR rowid IN ('+#PivotINColumnList+N'))pvt
)q2
ON q1.memberid = q2.memberid
'
PRINT #SQL
EXECUTE sp_executesql #SQL

I have a version of Postgres db wise doing this work. Here is my sample of code.
DROP TABLE IF EXISTS x;
CREATE TABLE x ( member NUMERIC , contract_start DATE, contract_end DATE);
INSERT INTO x VALUES( 1, '1/1/2011', '12/30/2011' )
,( 1, '1/1/2012', '12/30/2012' )
,( 1, '1/1/2013', '12/30/2013' )
,( 2, '7/1/2012', '12/30/2012' )
,( 2, '1/1/2013', '12/30/2013' )
,( 3, '1/1/2012', '12/30/2012' )
,( 3, '1/1/2013', '12/30/2013' )
,( 3, '8/1/2013', '12/30/2013' )
,( 3, '8/1/2013', '12/30/2013' );
-- CREATE LANGUAGE 'plpgsql';
-- DROP SEQUENCE IF EXISTS seq;
-- CREATE SEQUENCE seq;
CREATE OR REPLACE FUNCTION make_table() RETURNS void AS
$BODY$
DECLARE
i RECORD;
colcnt INTEGER;
BEGIN
DROP TABLE IF EXISTS tmptable;
SELECT max(count) INTO colcnt FROM (SELECT count(*) FROM x GROUP BY member) a;
EXECUTE 'CREATE TABLE tmptable (member integer ,' ||
(SELECT array_to_string(array_agg(x1.col1 || ' date, ' || x1.col2 || ' date'), ', ')
FROM (SELECT 'contract_start' || col col1
, 'contract_end'|| col col2 FROM generate_series(1,colcnt) t(col) ) x1 ) || ')';
EXECUTE 'INSERT INTO tmptable (member) SELECT DISTINCT member FROM x';
FOR i IN SELECT * FROM x ORDER BY member LOOP
PERFORM setval('seq',1);
EXECUTE 'UPDATE tmptable SET ' || x1.col
FROM (SELECT array_to_string(array_agg(' contract_start'
|| nextval('seq')-1 || ' = ''' || i.contract_start || ''', contract_end'
|| currval('seq')-1 || ' = ''' || i.contract_end ), ''', ') || ''' WHERE member = ' || member || ';' col
FROM x WHERE member = i.member GROUP BY member) x1;
END LOOP;
END;
$BODY$ LANGUAGE plpgsql;
SELECT * FROM make_table();
SELECT * FROM tmptable;
This is the first time I am answering. Hope this is relevant. (please run the commented only once).
Further the process of calling function each time on insert, update or delete can be automated with trigger. The following code will do that on replace of above one.
-- following commented lines for first time run :
-- CREATE LANGUAGE 'plpgsql';
-- DROP SEQUENCE IF EXISTS seq;
-- CREATE SEQUENCE seq;
-- DROP FUNCTION IF EXISTS make_table();
CREATE OR REPLACE FUNCTION make_table() RETURNS TRIGGER AS
$BODY$
DECLARE
i RECORD;
colcnt INTEGER;
BEGIN
DROP TABLE IF EXISTS tmptable;
SELECT max(count) INTO colcnt FROM (SELECT count(*) FROM x GROUP BY member) a;
EXECUTE 'CREATE TABLE tmptable (member integer ,' ||
(SELECT array_to_string(array_agg(x1.col1 || ' date, ' || x1.col2 || ' date'), ', ')
FROM (SELECT 'contract_start' || col col1
, 'contract_end'|| col col2 FROM generate_series(1,colcnt) t(col) ) x1 ) || ')';
EXECUTE 'INSERT INTO tmptable (member) SELECT DISTINCT member FROM x';
FOR i IN SELECT * FROM x ORDER BY member LOOP
PERFORM setval('seq',1);
EXECUTE 'UPDATE tmptable SET ' || x1.col
FROM (SELECT array_to_string(array_agg(' contract_start'
|| nextval('seq')-1 || ' = ''' || i.contract_start || ''', contract_end'
|| currval('seq')-1 || ' = ''' || i.contract_end ), ''', ') || ''' WHERE member = ' || member || ';' col
FROM x WHERE member = i.member GROUP BY member) x1;
END LOOP;
RETURN new;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER create_tmptable AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE
ON x FOR STATEMENT EXECUTE PROCEDURE make_table();
-- For Test insert:
INSERT INTO x VALUES( 4, '1/1/2011', '12/30/2011' );
SELECT * FROM tmptable;

Related

cursor for loop & dynamic SQL - Snowflake

I'm attempting to write a procedure that takes in a list of tables and date_column to create some row_counts by calendar dates for reconciliation purposes.
SELECT t.*
FROM (
VALUES ('tbl1', 'created_date')
, ('tbl2', 'modify_date')
, ('tbl3', 'last_seen_date')
) t(tbl, dt)
+----+--------------+
|TBL |DT |
+----+--------------+
|tbl1|created_date |
|tbl2|modify_date |
|tbl3|last_seen_date|
+----+--------------+
I'm connected to Snowflake via a JDBC connection using Datagrip - so I assume I need to follow the classic SnowSQL part of the documentation:
https://docs.snowflake.com/en/developer-guide/snowflake-scripting/loops.html#cursor-based-for-loops
EXECUTE IMMEDIATE $$
DECLARE
dt text
, tbl text;
c1 CURSOR FOR SELECT dt, tbl from t;
BEGIN
FOR record in c1 DO
dt := record.dt
tbl := record.tbl
stmt =: 'SELECT COUNT(*)' ||
CONCAT(', DAYOFMONTH(', $dt, ')') ||
CONCAT('\n FROM ', $tbl) ||
CONCAT('\n WHERE YEAR(', $dt, ')', ' = YEAR(CURRENT_DATE)') ||
CONCAT('\n AND MONTH(', $dt, ')', ' = MONTH(CURRENT_DATE)') ||
'\n GROUP BY' ||
CONCAT('\n DAYOFMONTH(', $dt, ')')
EXECUTE IMMEDIATE stmt -- will adapt this to be an update statement eventually.
END FOR
end;
$$
This returns a SQL Compilation error, I've tried a few different variations of this but I'm none the wiser on how to proceed.
Instead of concatenating the query string which makes it almost unreadable it could be rewritten using bind variables:
DECLARE
dt text;
tbl text;
stmt text;
c1 CURSOR FOR SELECT dt, tbl from t;
BEGIN
FOR record in c1 DO
dt := record.dt;
tbl := record.tbl;
stmt := 'INSERT INTO result(cnt, day_of_month)
SELECT COUNT(*), DAYOFMONTH(IDENTIFIER(?)) AS day_of_month
FROM TABLE(?)
WHERE YEAR(IDENTIFIER(?)) = YEAR(CURRENT_DATE)
AND MONTH(IDENTIFIER(?)) = MONTH(CURRENT_DATE)
GROUP BY day_of_month';
EXECUTE IMMEDIATE :stmt USING (dt, tbl, dt, dt);
RETURN stmt;
END FOR;
END;
If column or table is parameter it should be wrapped with IDENTIFIER/TABLE funtion.
For sample data:
CREATE OR REPLACE TABLE t AS
SELECT 'col1' AS dt, 'tab1' AS tbl UNION ALL
SELECT 'col2' AS dt, 'tab1' ;
CREATE TABLE tab1(col1 DATE, col2 DATE) AS
SELECT CURRENT_DATE(), CURRENT_DATE()-40;
CREATE TABLE result(cnt INT, day_of_month INT);
SELECT * FROM result;
There are lots of minor issues like missing semicolons etc. Here is the fixed script:
DECLARE
dt text;
tbl text;
stmt text;
c1 CURSOR FOR SELECT dt, tbl from t;
BEGIN
FOR record in c1 DO
dt := record.dt;
tbl := record.tbl;
stmt := 'SELECT COUNT(*)' ||
CONCAT(', DAYOFMONTH(', dt, ')') ||
CONCAT('\n FROM ', tbl) ||
CONCAT('\n WHERE YEAR(', dt, ')', ' = YEAR(CURRENT_DATE)') ||
CONCAT('\n AND MONTH(', dt, ')', ' = MONTH(CURRENT_DATE)') ||
'\n GROUP BY' ||
CONCAT('\n DAYOFMONTH(', dt, ')');
-- EXECUTE IMMEDIATE :stmt;
RETURN stmt;
END FOR;
END;

Oracle dynamic query (return or select) result as table

How can I show the result of running a dynamic query as a table in the output?
I want to show the result of the following query as a table in the output.
my table :
create table myTable(ROW_NAME varchar(10),COLUMN_NAME varchar(10),COLUMN_NAME_VALUE varchar(10));
table data :
insert into myTable (ROW_NAME,COLUMN_NAME,COLUMN_NAME_VALUE)
select 'ROW1','COL1','R1C1' from dual
union all select 'ROW1','COL2','R1C2' from dual
union all select 'ROW1','COL3','R1C3' from dual
union all select 'ROW2','COL1','R2C1' from dual
union all select 'ROW2','COL2','R2C2' from dual
union all select 'ROW2','COL3','R2C3' from dual
union all select 'ROW3','COL1','R3C1' from dual
union all select 'ROW3','COL2','R3C3' from dual
union all select 'ROW3','COL3','R3C3' from dual
my dynamic query :
DECLARE
mycols VARCHAR2(1000);
sqlCommand varchar2(1000);
TYPE PivotCurTyp IS REF CURSOR;
pivot_cv PivotCurTyp;
type pivotted is record (row_name myTable.row_name%type, col1 myTable.column_name_value%type, col2 myTable.column_name_value%type, col3 myTable.column_name_value%type);
piv_rec pivotted;
BEGIN
select (select LISTAGG('''' || COLUMN_NAME || '''', ',') from myTable group by ROW_NAME FETCH FIRST 1 ROWS ONLY) into mycols from dual;
select Concat('select * from myTable pivot ( max (COLUMN_NAME_VALUE) for COLUMN_NAME in (',Concat(mycols,')) ORDER BY ROW_NAME')) into sqlCommand from dual;
DBMS_OUTPUT.PUT_LINE(sqlCommand);
OPEN pivot_cv FOR sqlCommand;
LOOP
FETCH pivot_cv INTO piv_rec;
EXIT WHEN pivot_cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('ROW_NAME: ' || piv_rec.ROW_NAME || ' COL1: ' ||
piv_rec.COL1 || ' COL2: ' || piv_rec.COL2 || ' COL3: ' || piv_rec.COL3);
END LOOP;
CLOSE pivot_cv;
END;
/
demo in db<>fiddle
Thanks for any help
Maybe I misunderstood, I guess what you want is this?
select 'ROW_NAME ' || t1.row_name || ' ' || listagg(t1.column_name || ': ' || t1.column_name_value, ' ')
within group(order by t1.column_name)
from myTable t1
group by t1.row_name
order by t1.row_name

oracle dynamic pivot error: SQL command not properly ended

I have a table whose data is obtained according to the desired output with pivot. But I want to create the number of columns dynamically.
my table :
create table myTable(ROW_NAME varchar(10),COLUMN_NAME varchar(10),COLUMN_NAME_VALUE varchar(10));
table data :
insert into myTable (ROW_NAME,COLUMN_NAME,COLUMN_NAME_VALUE)
select 'ROW1','COL1','R1C1' from dual
union all select 'ROW1','COL2','R1C2' from dual
union all select 'ROW1','COL3','R1C3' from dual
union all select 'ROW2','COL1','R2C1' from dual
union all select 'ROW2','COL2','R2C2' from dual
union all select 'ROW2','COL3','R2C3' from dual
union all select 'ROW3','COL1','R3C1' from dual
union all select 'ROW3','COL2','R3C3' from dual
union all select 'ROW3','COL3','R3C3' from dual
my query :
select * from myTable
pivot (
max (COLUMN_NAME_VALUE)
for COLUMN_NAME
in (
'COL1' as COL1,'COL2' as COL2,'COL3' as COL3
)
)
ORDER BY ROW_NAME;
The above query works but I want to get the columns dynamically.
my dynamic query :
DECLARE
mycols VARCHAR2(1000);
sqlCommand varchar2(1000);
TYPE PivotCurTyp IS REF CURSOR;
pivot_cv PivotCurTyp;
piv_rec mytable%ROWTYPE;
BEGIN
select (select LISTAGG(COLUMN_NAME, ',') from myTable group by ROW_NAME FETCH FIRST 1 ROWS ONLY) into mycols from dual;
select Concat('select * from myTable pivot ( max (COLUMN_NAME_VALUE) for COLUMN_NAME in (',Concat(mycols,')) ORDER BY ROW_NAME;')) into sqlCommand from dual;
OPEN pivot_cv FOR sqlCommand;
LOOP
FETCH pivot_cv INTO piv_rec;
EXIT WHEN pivot_cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('ROW_NAME: ' || piv_rec.ROW_NAME || ' COL1: ' ||
piv_rec.COLUMN_NAME_VALUE || 'COL2: ' || piv_rec.COLUMN_NAME_VALUE || 'COL3: ' || piv_rec.COLUMN_NAME_VALUE);
END LOOP;
CLOSE pivot_cv;
END;
/
Note : The equivalent of the above query can be generated on SQL Server and I have created it.
demo in db<>fiddle
Thanks for any help
There are 3 problems in your script:
semicolon-terminated dynamic query (that's the cause of "SQL command not properly ended")
identifiers in in clause instead of string literals (you can use 'foo' or 'foo' as foo but not foo alone)
improper piv_rec type - use table format after pivot, not before pivot
Summary:
DECLARE
mycols VARCHAR2(1000);
sqlCommand varchar2(1000);
TYPE PivotCurTyp IS REF CURSOR;
pivot_cv PivotCurTyp;
type pivotted is record (row_name myTable.row_name%type, col1 myTable.column_name_value%type, col2 myTable.column_name_value%type, col3 myTable.column_name_value%type);
piv_rec pivotted;
BEGIN
select (select LISTAGG('''' || COLUMN_NAME || '''', ',') from myTable group by ROW_NAME FETCH FIRST 1 ROWS ONLY) into mycols from dual;
select Concat('select * from myTable pivot ( max (COLUMN_NAME_VALUE) for COLUMN_NAME in (',Concat(mycols,')) ORDER BY ROW_NAME')) into sqlCommand from dual;
DBMS_OUTPUT.PUT_LINE(sqlCommand);
OPEN pivot_cv FOR sqlCommand;
LOOP
FETCH pivot_cv INTO piv_rec;
EXIT WHEN pivot_cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('ROW_NAME: ' || piv_rec.ROW_NAME || ' COL1: ' ||
piv_rec.COL1 || ' COL2: ' || piv_rec.COL2 || ' COL3: ' || piv_rec.COL3);
END LOOP;
CLOSE pivot_cv;
END;
/
updated db fiddle (BTW composing fiddle was very motivating to help)

Getting a count by value of all columns in a table using Oracle SQL

For various reasons the organisation I work for has data stored on both Oracle and MS SQL server databases. We are moving some static historical data over and I have to check that the data has been moved properly.
The Query below checks the data in SQL server and produces a table listing counts of all the values in each column of the table.
Due to formatting differences in Oracle I will need to group by two other columns Year and Iteration_count . I have not been able to get a loop through of all columns in a table working in Oracle as my experience is pretty much limited to SQL Server
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL = STUFF((SELECT ' UNION SELECT ''' + name
+ ''' AS [Column], '
+ 'CAST(' + QUOTENAME(Name)
+ ' AS NVARCHAR(MAX)) AS [ColumnValue], COUNT(*) AS [Count] FROM '
+'dbo.HES_APC_ACP_9798'
+' where (NUMACP IS NOT NULL AND NOT (NUMACP = 0) ) '
+' GROUP BY ' + QUOTENAME(Name)
--+'Order By [Column],[ColumnValue]'
FROM sys.columns
WHERE object_id = Object_id('dbo.HES_APC_ACP_9798' )
FOR XML PATH ('')), 1, 7, '');
EXECUTE sp_executesql #SQL;
This loop on user_tab_columns should help:
declare
v_table varchar2(30) := 'TEST';
v_sql varchar2(32767);
begin
for r in (select column_name name from user_tab_cols
where table_name=v_table order by column_id)
loop
v_sql := v_sql||' union all select '''||r.name||''' col_name, to_char('
||r.name||') col_value, count(1) cnt from '||v_table
||' group by '||r.name||chr(13);
end loop;
v_sql := ltrim(v_sql, ' union all ');
dbms_output.put_line(v_sql);
end;
Test table:
create table test (col1 varchar2(10), col2 number(5), col3 date);
insert into test values ('ABC', 1, null);
insert into test values ('DEF', 1, date '2015-06-18');
Executing first PLSQL block outputs:
select 'COL1' col_name, to_char(COL1) col_value, count(1) cnt from TEST group by COL1
union all select 'COL2' col_name, to_char(COL2) col_value, count(1) cnt from TEST group by COL2
union all select 'COL3' col_name, to_char(COL3) col_value, count(1) cnt from TEST group by COL3
Output of this query:
COL_NAME COL_VALUE CNT
-------- ------------ ----------
COL1 DEF 1
COL1 ABC 1
COL2 1 2
COL3 1
COL3 15/06/18 1
Use all_tab_cols and add filter for owner if you read data from other schema. You can also run generated query using execute immediate statement.

dynamic table name in select statement

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