简体   繁体   中英

Getting ORA-00904 invalid identifier with pl/sql loop

When attempting to use a list of tables as segment names for a query against dba_segments I get an ORA-00904: invalid identifier error .

I've tried moving around various quotes in case it's a syntax error, but I'm not sure what the issue might be.

declare
v_sql_c1 varchar2 (1000);
V_dblink varchar2(100) := 'DB1';

begin

for c1 in (select * from TABLE_LIST)
       loop
execute immediate' select /*+parallel*/ bytes from dba_extents '|| '@' ||V_dblink ||' a '
||' where segment_name ='||
c1.table_name
into v_sql_c1;
dbms_output.put_line(v_sql_c1);
end loop;
end;
/

I would like ideally for this to report a value for 'bytes' in every row in the table_name column of table_list , which is the same as the segment_nam e column of dba_segments.

Can anyone help?

This is what you currently have:

SQL> CREATE TABLE table_list (table_name VARCHAR2 (20));

Table created.

SQL> INSERT INTO table_list  VALUES ('EMP');

1 row created.

SQL> set serveroutput on;
SQL> DECLARE
  2     v_sql_c1  VARCHAR2 (1000);
  3     V_dblink  VARCHAR2 (100) := 'DB1';
  4     v_sql     VARCHAR2 (1000);
  5  BEGIN
  6     FOR c1 IN (SELECT * FROM TABLE_LIST)
  7     LOOP
  8        v_sql :=
  9              ' select /*+parallel*/ bytes from dba_extents '
 10           || '@'
 11           || V_dblink
 12           || ' a '
 13           || ' where segment_name ='
 14           || c1.table_name;
 15
 16        DBMS_OUTPUT.put_line (v_sql);
 17
 18  --      EXECUTE IMMEDIATE v_sql INTO v_sql_c1;
 19
 20        DBMS_OUTPUT.put_line (v_sql_c1);
 21     END LOOP;
 22  END;
 23  /
select /*+parallel*/ bytes from dba_extents @DB1 a  where segment_name =EMP

PL/SQL procedure successfully completed.

SQL>

See? An invalid SELECT statement.

But, if you

  • remove space in front of a database link name
  • apply single quotes to segment_name

you'll get something that might work:

SQL> DECLARE
  2     v_sql_c1  VARCHAR2 (1000);
  3     V_dblink  VARCHAR2 (100) := 'DB1';
  4     v_sql     VARCHAR2 (1000);
  5  BEGIN
  6     FOR c1 IN (SELECT * FROM TABLE_LIST)
  7     LOOP
  8        v_sql :=
  9              ' select /*+parallel*/ bytes from dba_extents'
 10           || '@'
 11           || V_dblink
 12           || ' a '
 13           || ' where segment_name ='
 14           || CHR (39)
 15           || c1.table_name
 16           || CHR (39);
 17
 18        DBMS_OUTPUT.put_line (v_sql);
 19
 20        --      EXECUTE IMMEDIATE v_sql INTO v_sql_c1;
 21
 22        DBMS_OUTPUT.put_line (v_sql_c1);
 23     END LOOP;
 24  END;
 25  /
select /*+parallel*/ bytes from dba_extents@DB1 a  where segment_name ='EMP'

PL/SQL procedure successfully completed.

SQL>

Basically, you should always display statement you'll be running as a dynamic SQL, make sure it is correct, and then actually EXECUTE IMMEDIATE it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM