Say I have several tables that all start with 'PLAYER_' and I am trying to loop through all of those tables to get tables names and then loop again to get a value of a column in all of these tables.
This column exists in all tables so I want to use nested FOR loops to achieve that.
Here is what I have so far but it does not seem to work:
DECLARE
LOG_ID NUMBER;
TBL_NME VARCHAR2(30);
V_STRNG VARCHAR2(4000);
BEGIN
FOR i IN (SELECT TABLE_NAME FROM USER_TABLES WHERE TABLE_NAME LIKE 'PLAYER_%') LOOP
TBL_NME := i.TABLE_NAME;
DBMS_OUTPUT.PUT_LINE('TABLE EXTRACTED IS ' || TBL_NME);
FOR j IN(SELECT LOG_ID FROM i.TABLE_NAME) LOOP
V_EXEC_OBJ_STRNG := 'SELECT LOG_ID FROM ' || i.TABLE_NAME;
EXECUTE IMMEDIATE V_STRNG INTO LOG_ID;
DBMS_OUTPUT.PUT_LINE('LOG_ID IS ' || LOG_ID || ' FOR TABLE ' || i.TABLE_NAME);
END LOOP;
END LOOP;
END;
/
You can probably get away with just one loop ...
Example
create table player_01 ( id, name )
as
select level, dbms_random.string( 'x', 25 )
from dual
connect by level <= 10 ;
create table player_02 ( id, name )
as
select level, dbms_random.string( 'x', 25 )
from dual
connect by level <= 11 ;
create table player_03 ( id, name )
as
select level, dbms_random.string( 'x', 25 )
from dual
connect by level <= 12 ;
Anonymous block:
-- find all relevant tables and retrieve the highest id values
declare
logid number := 0 ;
tablename varchar2( 30 ) := '' ;
v_string varchar2( 4000 ) := '' ;
begin
for r in (
select table_name from user_tables
where table_name like 'PLAYER%'
order by table_name
) loop
-- dbms_output.put_line( ' current table -> ' || r.table_name ) ;
v_string := 'select max( id ) as logid from ' || r.table_name;
execute immediate v_string into logid ;
dbms_output.put_line( 'log id is ' || logid || ' for table ' || r.table_name ) ;
end loop ;
end ;
/
-- result
log id is 10 for table PLAYER_01
log id is 11 for table PLAYER_02
log id is 12 for table PLAYER_03
According to your comment, there are several LOGIDs in each PLAYER_ table. Maybe the following example is closer to the "real thing". (And: the anonymous block has nested loops ... ( tested with Oracle 12c and 11g, dbfiddle here ).
Tables
create table player_01 ( id, details, logid )
as
select level, dbms_random.string( 'x', 25 ), abs( dbms_random.random() )
from dual
connect by level <= 3 ;
create table player_02 ( id, details, logid )
as
select level, dbms_random.string( 'x', 25 ), abs( dbms_random.random() )
from dual
connect by level <= 4 ;
create table player_03 ( id, details, logid )
as
select level, dbms_random.string( 'x', 25 ), abs( dbms_random.random() )
from dual
connect by level <= 4 ;
Sample data in PLAYER_01 / PLAYER_02 / PLAYER_03
select * from player_01 ;
ID DETAILS LOGID
1 VZAQXPFCQK3U2F0RL32I31N40 699945134
2 32QWFFMUCF1DL6E3Z5QM4DSWY 1635628934
3 48GWBETOLUSDEFA3SMY061NUO 1237793316
select * from player_02;
ID DETAILS LOGID
1 HS827U4VCY853N8DKTI98J82D 1993524164
2 XLYS0XPJG0IQP4BNKDQ0ZITPA 1665941353
3 DWVVR5O6N5T1HP5MDYHVH3NZJ 1129581845
4 L7N8HCPVTHP466WJ5TCQ04YHE 794237444
select * from player_03;
ID DETAILS LOGID
1 SYVX5G2FE5IC1MI6TCSAHNOUU 720476135
2 4IQZIG6DAUCWW3APJY5OZ63TF 287457960
3 525NMZFVGLWKIT7EIFA41C8MB 784891618
4 0XHJXV2O4TCQQSITOTIQCO3AA 1578737054
Anonymous block
declare
logid number := 0 ;
tablename varchar2( 30 ) := '' ;
v_string1 varchar2( 4000 ) := '' ;
v_string2 varchar2( 4000 ) := '' ;
rowcount number := 0 ;
begin
for r in (
select table_name from user_tables
where table_name like 'PLAYER%'
order by table_name
) loop
v_string1 := 'select count(*) from ' || r.table_name ;
execute immediate v_string1 into rowcount ;
dbms_output.put_line( rowcount ) ;
for rn in 1 .. rowcount
loop
-- dbms_output.put_line( rn ) ;
v_string2 := 'select logid from ( '
|| 'select logid, row_number() over ( order by id ) rn '
|| ' from ' || r.table_name || ' )'
|| ' where rn = ' || rn;
-- dbms_output.put_line( v_string2 ) ;
execute immediate v_string2 into logid ;
dbms_output.put_line( 'log id is ' || logid || ' for table ' || r.table_name ) ;
end loop ;
end loop ;
end ;
/
dbms_output:
3
log id is 699945134 for table PLAYER_01
log id is 1635628934 for table PLAYER_01
log id is 1237793316 for table PLAYER_01
4
log id is 1993524164 for table PLAYER_02
log id is 1665941353 for table PLAYER_02
log id is 1129581845 for table PLAYER_02
log id is 794237444 for table PLAYER_02
4
log id is 720476135 for table PLAYER_03
log id is 287457960 for table PLAYER_03
log id is 784891618 for table PLAYER_03
log id is 1578737054 for table PLAYER_03
The second query string (v_string2) looks a bit like this (maybe a bit easier to read than all the string parts and ||):
select logid
from (
select
logid
, row_number() over ( order by id ) rn
from player_01
) where rn = 1
;
-- query result
LOGID
1338793259
Query in the inner loop (answering the question in your comment)
The subquery uses row_number() - see documentation:
"ROW_NUMBER is an analytic function. It assigns a unique number to each row to which it is applied (either each row in the partition or each row returned by the query), in the ordered sequence of rows specified in the order_by_clause, beginning with 1."
We are using this to get consecutive numbers, numbering the LOGIDs as it were. Then, we use the RN values in the WHERE clause (of the outer select), and compare them to the inner FOR loop's "rn" value.
select
logid
, row_number() over ( order by id ) rn
from player_01 ;
-- result
LOGID RN
1775991812 1
262095022 2
2090118607 3