嵌套循环从 Oracle 中的多个表中检索值

Nested Loops to Retrieve a value from several tables in Oracle

假设我有几个表都以 'PLAYER_' 开头,我试图遍历所有这些表以获取表名,然后再次循环以获取所有这些表中列的值.

此列存在于所有表中,因此我想使用嵌套的 FOR 循环来实现。

这是我目前所拥有的,但它似乎不起作用:

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;
/

你可能只需要一个循环就可以逃脱......

例子

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 ;

匿名块:

-- 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

Dbfiddle here.

根据您的评论,每个PLAYER_中有几个LOGID_ table。也许下面的例子更接近"real thing"。 (并且:匿名块具有嵌套循环......(使用 Oracle 12c 和 11g 测试,dbfiddle here)。

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 ;

样本数据在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

匿名块

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

第二个查询字符串 (v_string2) 看起来有点像这样(可能比所有字符串部分和 || 更容易阅读):

select logid
from (
  select 
    logid
  , row_number() over ( order by id ) rn
  from player_01 
) where rn = 1
;
-- query result
LOGID
1338793259 

在内循环中查询 (回答您评论中的问题)

子查询使用 row_number() - 参见 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."

我们正在使用它来获取连续的数字,就像对 LOGID 进行编号一样。然后,我们在 WHERE 子句(外部 select 的)中使用 RN 值,并将它们与内部 FOR 循环的 "rn" 值进行比较。

select 
  logid
, row_number() over ( order by id ) rn
from player_01 ;

-- result
LOGID       RN
1775991812  1
262095022   2
2090118607  3