Вложенные циклы для извлечения значения из нескольких таблиц в Oracle - PullRequest
0 голосов
/ 17 октября 2018

Скажем, у меня есть несколько таблиц, которые все начинаются с '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;
/

1 Ответ

0 голосов
/ 17 октября 2018

Вы, вероятно, можете обойтись всего одним циклом ...

Пример

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 здесь.

Согласно вашему комментарию, в каждой таблице PLAYER_ есть несколько LOGID.Возможно, следующий пример ближе к «реальной вещи».(И еще: анонимный блок имеет вложенные циклы ... (протестировано с Oracle 12c и 11g, dbfiddle здесь ).

Таблицы

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 () - см. Документация :

"ROW_NUMBER - аналитическая функция. Она присваивает уникальный номер каждой строке, к которой она применяется (каждая строка в разделе или каждая строка, возвращаемаязапрос), в упорядоченной последовательности строк, указанных в order_by_clause, начиная с 1. "

Мы используем это для получения последовательных номеров, нумерация LOGID, как это было. Затем мы используем RNзначения в предложении WHERE (внешнего выбораct) и сравните их со значением "rn" внутреннего цикла FOR.

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

-- result
LOGID       RN
1775991812  1
262095022   2
2090118607  3
...