I have a query string that have execute immediate.
how can I Execute Immediate this PL/SQL?
query string = 'Execute immediate select ....';
Want do this: Execute immediate 'query string';
That became this: Execute immediate 'Execute immediate select ....;';
Do you know How can I do this?
Without commenting on whether it is normal or wise: yes, I believe you can do it. That is, I've never seen anything written about EXECUTE IMMEDIATE that suggested it is not re-entrant. Plus, it works if you try it.
Here is a simple, typical EXECUTE IMMEDIATE call:
DECLARE
l_count NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*) INTO :l_count FROM DBA_OBJECTS WHERE ROWNUM <= 100' INTO l_count;
DBMS_OUTPUT.PUT_LINE ('l_count = ' || l_count);
END;
Here is basically the same thing, but with EXECUTE IMMEDIATE calls nested to two levels:
DECLARE
l_outer_count NUMBER;
BEGIN
EXECUTE IMMEDIATE q'!
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*) INTO :x FROM DBA_OBJECTS WHERE ROWNUM <= 100' INTO :l_outer_count;
END;
!'
USING IN OUT l_outer_count;
DBMS_OUTPUT.PUT_LINE('l_outer_count = ' || l_outer_count);
END;
I have never encountered a need to do this.
Related
create or replace PROCEDURE INSSEL_TBL_TEST AS
BEGIN
DECLARE
TBL varchar2(50):= 'ESSCSHSTMTBPTEST2';
tblNm varchar2(50);
CURSOR tableIndexList IS
(select ES_INDEX_NM,ES_TBL_NM,ES_CRT_INDEX_STMT,ES_DROP_INDEX_STMT FROM ESSP.ESSINDEXCONF WHERE ES_TBL_NM = TBL);
BEGIN
FOR drpInd in tableIndexList LOOP
EXECUTE IMMEDIATE 'drpInd.ES_DROP_INDEX_STMT';
COMMIT;
END LOOP;
execute immediate ('insert into ESSPREP.' ||UPPER(TBL)|| ' select * from ESSP.' ||UPPER(TBL)|| '#ESSPREPLINKESSP');
FOR drpInd in tableIndexList Loop
execute immediate 'drpInd.ES_CRT_INDEX_STMT';
COMMIT;
END LOOP;
END;
END;
above is my procedure to drop index before insert statement, after that create back the index.But it not work,anyone can help ?
Line
EXECUTE IMMEDIATE 'drpInd.ES_DROP_INDEX_STMT';
is wrong. You're trying to use value from cursor but as a fact you're using string literal. To fix this error just remove quotes:
EXECUTE IMMEDIATE drpInd.ES_DROP_INDEX_STMT;
Also, as #XING said, commit is superfluous here.
Your syntax is not correct. See below:
create or replace PROCEDURE INSSEL_TBL_TEST
AS
TBL varchar2(50):= 'ESSCSHSTMTBPTEST2';
tblNm varchar2(50);
CURSOR tableIndexList IS
(select ES_INDEX_NM,ES_TBL_NM,ES_CRT_INDEX_STMT,ES_DROP_INDEX_STMT FROM ESSP.ESSINDEXCONF WHERE ES_TBL_NM = TBL);
BEGIN
FOR drpInd in tableIndexList LOOP
EXECUTE IMMEDIATE drpInd.ES_DROP_INDEX_STMT;
--COMMIT;-- DROP is a DDL hence no need for COMMIT
END LOOP;
execute immediate 'insert into ESSPREP.' ||UPPER(TBL)|| ' select * from ESSP.' ||UPPER(TBL)|| '#ESSPREPLINKESSP';
FOR drpInd in tableIndexList Loop
execute immediate drpInd.ES_CRT_INDEX_STMT;
END LOOP;
END;
I get tripped up using dynamic sql and quotes. When I dbms_output the sql_stmt, it outputs valid/working code. How should the sql_stmt := line be written so that I can dynamically execute it? I have tried ":1 using" bind variable syntax as well with no luck.
The point of this code is to gather stats for a subset of tables.
set serveroutput on
--create this test table for working example.
--create table test3 as select table_name from user_tables where rownum <= 5;
declare
sql_stmt varchar2(500);
begin
for rec in (select table_name from test3)
loop
sql_stmt := 'exec dbms_stats.gather_table_stats (''SCOTT'',''' || rec.table_name || ''')';
dbms_output.put_line(sql_stmt);
execute immediate sql_stmt; -- <---Error is here---
end loop;
end;
The errors I get from the execute immediate sql_stmt; line is:
ORA-00900: invalid SQL statement
ORA-06512: at line 8
EXEC is an SQL*Plus command. You may want to wrap the call to DBMS_STATS.GATHER_TABLE_STATS in an anonymous block instead if you insist on using dynamic SQL.
However, you should be able to call the procedure directly, like so:
declare
sql_stmt varchar2(500);
begin
for rec in (select table_name from test3)
loop
dbms_stats.gather_table_stats ('SCOTT',rec.table_name);
end loop;
end;
Use
sql_stmt := 'BEGIN dbms_stats.gather_table_stats (''SCOTT'','''
|| rec.table_name || '''); END;';
instead.
CREATE OR REPLACE PROCEDURE ResetVersionNumberValue IS
sql_stmt VARCHAR2(2000);
BEGIN
FOR sql_stmt IN (select 'update '|| table_name ||
' set version = 0'
from user_tables
where table_name like 'MY_%')
LOOP
EXECUTE IMMEDIATE sql_stmt;
END LOOP;
COMMIT;
END;
Why the about procedure is not compiling? Its giving error saying
Error(8,26): PLS-00382: expression is of wrong type
How to resolve this?
Two things:
You need to remember that when iterating a cursor it returns a ROW, not a VALUE, and
The SELECT in the cursor needs to give a name to the value in the row being generated by the cursor.
Try:
CREATE OR REPLACE PROCEDURE ResetVersionNumberValue IS
BEGIN
FOR aRow IN (select 'update '|| table_name ||
' set version = 0' AS SQL_STMT
from user_tables
where table_name like 'MY_%')
LOOP
EXECUTE IMMEDIATE aRow.SQL_STMT;
END LOOP;
COMMIT;
END;
Share and enjoy.
CREATE OR REPLACE PROCEDURE ResetVersionNumberValue IS
BEGIN
FOR sql_stmt IN (
select 'update '|| table_name || ' set version = 0' as x
from user_tables
where table_name like 'MY_%')
LOOP
EXECUTE IMMEDIATE sql_stmt.x;
END LOOP;
COMMIT;
END;
I need a help on this.
I am trying to create a pl/sql anonymous block and when I run that it shows its completed but it don't run the code. It should give me an error saying name is already used by an existing object. Can someone help me on this.
I am actually creating procedures but just trying this code as a sample.
DECLARE
V_REF_TBL VARCHAR2(100);
V_SQL LONG;
begin
V_REF_TBL :='My_TABLE';
v_SQL :='truncate table '||V_REF_TBL ;
EXECUTE IMMEDIATE V_SQL;
EXECUTE IMMEDIATE 'CREATE TABLE '|| V_REF_TBL ||' parallel 9 nologging pctfree 0 as
select * from dual';
End;
Possibly you're looking for this:
<<my_block>>
Declare
table_name varchar2(30);
counter number;
Begin
table_name := 'my_table';
select count(*)
into counter
from user_tables
where table_name = Upper(Trim(my_block.table_name)) and
dropped = 'NO';
if counter = 0
then
execute immediate 'create table '||table_name||' as ... etc';
else
execute immediate 'truncate table '||table_name;
execute immediate 'insert into '||table_name' select ... etc';
end if;
end my_block;
We have a sql script to update a set of sequences after seed data populated our tables. The code below would not work:
declare
cursor c1 is
select
'select nvl(max(id),0) from '||uc.table_name sql_text,
uc.table_name||'_SEQ' sequence_name
from
user_constraints uc,
user_cons_columns ucc
where uc.constraint_type='P'
and ucc.constraint_name = uc.constraint_name
and ucc.column_name='ID'
and uc.owner='ME';
alter_sequence_text varchar2(1024);
TYPE generic_cursor_type IS REF CURSOR;
max_id number;
c2 generic_cursor_type;
begin
for r1 in c1 loop
open c2 for r1.sql_text;
fetch c2 into max_id;
close c2;
if( max_id != 0 ) then
dbms_output.put_line( 'seq name = '||r1.sequence_name );
execute immediate 'alter sequence '||r1.sequence_name||' increment by '||to_char(max_id);
dbms_output.put_line( 'max_id = '||to_char(max_id) );
execute immediate 'select '||r1.sequence_name||'.nextval from dual';
dbms_output.put_line( 'sequence value = '||to_char(next_id) );
execute immediate 'alter sequence '||r1.sequence_name||' increment by 1';
dbms_output.put_line( 'sequence: '||r1.sequence_name||' is at '||to_char(max_id+1) );
end if;
end loop;
end;
After searching I found a reference that stated I needed to change the line:
execute immediate 'select '||r1.sequence_name||'.nextval from dual'
and add 'into next_id;' (of course declaring next_id appropriately) so the result would be:
execute immediate 'select '||r1.sequence_name||'.nextval from dual into next_id;
I've only dealt lightly with pl/sql and sql in general and am interested to know why this change was necessary to make the script work correctly.
Thanks.
When you are using select inside PL/SQL block you have to place data returned by that select statement somewhere. So you have to declare a variable of appropriate data type and use select into clause to put data select returns into that variable even if select statement is executed by execute immediate statement.
Examples
declare
x number;
begin
select count(*)
into x
from all_objects;
end;
declare
x number;
begin
execute immediate 'select count(*)from all_objects' into x;
end;
So your execute immediate statement would be
execute immediate 'select '||sequence_name||'.nextval from dual' into newseqval;
If you are using Oracle 11g onward you can assign sequence's value directly to a variable, there is no need of using select into clause.
declare
x number;
begin
x := Sequence_Name.nextval;
end;
select seq_name.nextval from dual implies the implicit cursor creation and the results of the cursor should be fetched somewhere so you need fetch it into any externally declared bind variable.