syntax trouble with a simple dyanamic pl/sql insert statement. my code is as follows.
sql_stmt VARCHAR2(500);
sql_stmt := 'PKG_COLLECTION.COLLECTION_INS_01(:1,:2,:3,:4,:5,:6)';
execute immediate sql_stmt using
IN OUT V_P1,
IN OUT V_P2,
IN OUT V_P3,
IN OUT V_P4,
IN OUT V_P5,
IN OUT V_P6;
(error: ORA-00900: invalid SQL statement)
What should the actual syntax look like?
You just need to change this part to make it into PL/SQL instead of SQL:
sql_stmt := 'begin PKG_COLLECTION.COLLECTION_INS_01(:1,:2,:3,:4,:5,:6); end;';
Since the executed statement is not dynamic, I strongly suggest you don't use execute immediate. Instead, I'd go with a simple
PKG_COLLECTION.COLLECTION_INS_01(V_P1,V_P2,V_P3,V_P4,V_P5,V_P6);
which achieves the same thing, but is cleaner and results in an invalid procedure/package/function if the signature of PKG_COLLECTION.COLLECTION_INS_01 changes.
Related
I am using execute immediate to create table and use this table into my code to insert some values when i run this code .it gives me error that table and view does not exist.why?. this code has ability to create table because when i use drop and create table command with existing table by using execute immediate then my code works fine and when i just remove drop table syntax, my code does not work, Please help me to clear my concept about dynamic SQL-----------
SET serveroutput ON
DECLARE
ddl_table VARCHAR2(200);
r_emp SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();
v_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST('ACCT_ID',
'PARENT_ACCT_ID',
'CUST_ID',
'ACCT_NAME',
'BILLING_CYCLE_TYPE',
'PAID_FLAG',
'BILL_DELIVER_METHOD');
BEGIN
ddl_table := 'CREATE TABLE test123(
v_column VARCHAR2(50),
v_count NUMBER
)';
EXECUTE IMMEDIATE ddl_table;
DBMS_OUTPUT.ENABLE;
FOR i IN 1 .. v_array.COUNT LOOP
r_emp.EXTEND;
EXECUTE IMMEDIATE 'SELECT COUNT(*)
FROM account_profile
WHERE NOT REGEXP_LIKE(' ||v_array(i) || ',''[A-Za-z0-9.]'')'
INTO r_emp(i);
IF r_emp(i) <> 0 THEN
DBMS_OUTPUT.PUT_LINE(v_array(i) || ': ' || r_emp(i));
INSERT INTO test123 VALUES (v_array(i), r_emp(i));
END IF;
END LOOP;
END;
/
Error report -
ORA-06550: line 24, column 17:
PL/SQL: ORA-00942: table or view does not exist
Your problem is that the annonymous block is pre-validated (pre-compiled) before it is valid. Oracle will check all objects in use before executing it. Since you are creating test123 dynamically it doesn't exist so your insert statement fails.
You can instead, use an EXECUTE IMMEDIATE command to also insert the data on your test123 table.
The way you use the EXECUTE IMMEDIATE for an insert command is either concatenating the parameters or preparing them, I prefer the later. Like this
execute immediate 'insert into test123 values (:param1,:param2)' using v_array(i), r_emp(i);
Here is the official documentation for the EXECUTE IMMEDIATE command.
Though it shows how it works and explain the usage of it, it doesn't particularly answer you direct question on the comments.
So
can you explain :param1,:param2
Those are called "binding" parameters that will be replaced by the variables used after the using statement. It doesn't matter their name only the order in which they appear on the string. The number of parameters within the dynamic string needs to match the number of parameters after the using statement.
why we use it with : colon and what are these
The colon : there is just to make it easier for the parser to know what to replace and where when using the variables you provided after the using statement
Translating that execute immediate it would be something like this:
... values (:param1,:param2)' using v_array(i), r_emp(i)
Hey "execute immediate" whenever you see :param1 please replace it with the content of the variable I'm providing as v_array(i) and whenever you see :param2 please replace it with the content of the variable I'm providing as r_emp(i)
The below code returns error ORA-00942: table or view does not exist, I think may be because PL/SQL runtime engine(or something I don't know what) is trying to treat table_in as a Table but why would it do so, I have already table_in declared as variable.
The ex26011601 table exists with values in the same schema.
set serveroutput on
declare
function tabcount (table_in in varchar2)
return pls_integer
is
l_return pls_integer;
begin
select count(*) into l_return from table_in;
return l_return;
end;
begin
dbms_output.put_line(tabcount('ex26011601'));
end;
I understand EXECUTE IMMEDIATE would solve the purpose. What I am trying to get is why is it necessary and whats wrong with current statement that 'table_in' could not be treated as variable even after being declared in the scope. Or what is the reason why a variable is not expected there?
I understand EXECUTE IMMEDIATE would solve the purpose. What I am
trying to get is why is it necessary and whats wrong with current
statement that 'table_in' could not be treated as variable even after
being declared in the scope.
As per oracle documentation : Static SQL
A PL/SQL static SQL statement can have a PL/SQL identifier wherever its SQL counterpart can have a placeholder for a bind variable. The PL/SQL identifier must identify either a variable or a formal parameter.To use PL/SQL identifiers for table names, column names, and so on, use the EXECUTE IMMEDIATE statement
In PL/SQL, you need dynamic SQL to run when :
SQL whose text is unknown at compile time
For example, a SELECT statement that includes an identifier that is unknown at compile time (such as a table name) or a WHERE clause in
which the number of sub clauses is unknown at compile time.
SQL that is not supported as static SQL
Dynamic SQL
Yes, as you said oracle pl/sql syntax does not allowing that, pass table name by variable. As you also said you can do it only by dynamic sql and execute immediate:
execute immediate 'select count(*) from ' || table_in
into l_return;
Hi I have to execute a remote call ...
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO#DB_LINK()
... from a stored procedure.
As the value of DB_LINK is to be obtained during runtime. It should be executed dynamically. I tried to use
EXECUTE IMMEDIATE ' DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO#'||DB_LINK||'()';
But I get the following error
ORA-00900: invalid SQL statement
Can anyone advise me on how to execute the Stored Procedure dynamically?
The clue lies in the precise wording of the error message: invalid SQL statement. As the PL/SQL manual says, EXECUTE IMMEDIATE is for executing dynamic SQL statements.
You are executing a procedure call i.e. PL/SQL not SQL. So you need to pass an anonymous block to EXECUTE IMMEDIATE:
EXECUTE IMMEDIATE
'begin DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO#'||DB_LINK||'() ; end;'
;
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO takes no parameters, so the empty brackets are optional. By all means include them if they make you feel happier.
EXECUTE IMMEDIATE 'DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO#'||DB_LINK();
should work if DB_LINK is a global function returning a VARCHAR2 string.
I have implemented a certain feature in my application where the user can compose queries dynamically from the user interface by pushing around buttons and inserting some values here and there.
The user will not see the generated SQL statement at all.
I was wondering if there is a way to perhaps check the syntax and grammar (e.g. he opened a parantheses '(' and forgot to close it ) of the dynamically generated SQL to ensure that no run-time compilation errors would happen before actually executing the statement using EXECUTE IMMEDIATE.
You could use the dbms_sql.parse procedure to parse the SQL statement assuming the statement is DML not DDL. It would be rather unusual to parse a dynamic SQL statement using the dbms_sql package and then use EXECUTE IMMEDIATE to execute it rather than using dbms_sql.execute but nothing prevents you from mixing dbms_sql and execute immediate.
The code to just parse the SQL statement would be something like
DECLARE
l_cursor integer;
l_sql_stmt varchar2(1000) := <<some SQL statement>>;
BEGIN
l_cursor := dbms_sql.open_cursor;
dbms_sql.parse( l_cursor, l_sql_stmt, dbms_sql.native );
dbms_sql.close_cursor( l_cursor );
END;
You can also use explain plan, this is basically doing the first step of the execution.
SQL> explain plan for select * from dual;
Explained.
SQL is valid, you can also use the explain tables to get the tables, views etc, maybe even estimated run time ...
SQL> explain plan for select * from duall;
explain plan for select * from duall
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL is invalid, this is why ...
you can also use it in a dynamic statement
SQL> begin execute immediate 'explain plan for ' || ' select * from dual'; end;
2 /
PL/SQL procedure successfully completed.
As always use error-handling, e.g. write a little error log creater package or procedure what u call when it's needed.
DECLARE
my_stmt VARCHAR2(4000):='this will contain my statements';
BEGIN
'begin' || my_stmt || 'end';
EXCEPTION
WHEN OTHERS THEN
prc_my_error_log_creator();
END;
in the log_creator use for example the DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() func to get the stack's contain.
Regards
If i type my source tables name, data are copy into our target table:
'Create or Replace procedure p
(source_tab varchar2,target_tab varchar2)
As
query varchar2(200);
Type I_tab is table of varchar2(100000) index by binary_integer;
Rec_i I_tab;
Begin
query=’select * from’||source_tab;
Execute immediate query bulk collect into rec_i;
Forall i in rec_i.first..rec_i.last
Execute immediate’insert into’||target_tab||’values’||rec_i(i);
Commit;
End;
/
In the absence of anything useful like the actual compilation or runtime errors are we can do is guess.
As it happens your code has several obvious bloomers.
You appear to be using MS Word type smart quotes ’ whereas Oracle expects regular ASCII dumb quotes '. So that would be a compilation error.
The maximum size of a VARCHAR2 is 32767 so your nested table statement will hurl a compilation error.
You need to put spaces around the key words in the dynamic SQL. Otherwise you'll get a runtime error. So ’insert into’||target_tab||’values’ needs to 'insert into '||target_tab||' values ' . Make sure you check all the strings.
In PL/SQL the assignment operator is :=; = is the test for equality.
Less obvious, but we can't use EXECUTE IMMEDIATE in a FORALL. It's not a programmatic loop, and it needs to be a DML (SQL) statement: EXECUTE IMEMDIATE is PL/SQL. However you can do the same thing with
execute immediate
'insert into '|| target_tab ||
' select * from '|| source_tab