I have the following code in PLSQL:
Declare
tablename varchar2(20):='emp';
drop_stmt varchar2(2000);
begin
drop_stmt:='drop table :1 ;';
--dbms_output.put_line(drop_stmt);
execute immediate drop_stmt using tablename;
end;
Results in:
ORA-00903:invalid table name
ORA-06512: at line 8
However when I run:
drop table emp ;
it just successfully runs. What may be the cause of this error?
You must use this one:
drop_stmt:='drop table '||tablename; -- without ";" at the end of string
--dbms_output.put_line(drop_stmt);
execute immediate drop_stmt;
Related
I have a procedure that does a validation and inserts a record in a table. The procedure is breaking right after the INSERT statement when I try the following code:
EXECUTE IMMEDIATE V_SOME_STRNG || ' returning SOME_ID into :NEW_ID' returning into V_TRGT_ID;
I am trying to execute my INSERT statement which is stored in V_SOME_STRNG and assign the new record's ID to V_TRGT_ID. However, I am running into the following error:
ORA-00933: SQL command not properly ended
Any thoughts?
You don't need to repeat the returning into part, you need a using clause for your bind variable:
EXECUTE IMMEDIATE V_SOME_STRNG || ' returning SOME_ID into :NEW_ID' using out V_TRGT_ID;
Demo using a basic trigger to provide the ID:
create table t42 (some_id number, dummy varchar2(1));
create sequence s42 start with 42;
create trigger tr42 before insert on t42 for each row
begin
:new.some_id := s42.nextval;
end;
/
set serveroutput on
declare
v_some_strng varchar2(200) := 'insert into t42 (dummy) values (''X'')';
v_trgt_id number;
begin
EXECUTE IMMEDIATE V_SOME_STRNG || ' returning SOME_ID into :NEW_ID' using out V_TRGT_ID;
dbms_output.put_line('Returned ID: ' || v_trgt_id);
end;
/
which shows:
Returned ID: 42
PL/SQL procedure successfully completed.
You can only use returning into with the insert .. values ... pattern, not with insert ... select ...; so for instance changing the code above to use;
v_some_strng varchar2(200) := 'insert into t42 (dummy) select ''X'' from dual';
will get the error you originally reported:
ORA-00933: SQL command not properly ended
ORA-06512: at line 6
While you don't need to use returning into part, the OP problem most likely results from an error in the not shown content of the V_SOME_STRNG variable. Because you definitely can use returning into with execute immediate. Here is an example strait from the documentation:
sql_stmt := 'UPDATE emp SET sal = 2000 WHERE empno = :1 RETURNING sal INTO :2';
EXECUTE IMMEDIATE sql_stmt USING emp_id RETURNING INTO salary;
I stress the point again: it works. So if you have any troubles here check you dynamically generated SQL statement more thoroughly.
My test_queries table consist of 2 columns:fid and query_text.I want insert new row. And I return fid I inserted because I use it next question. But the code give me error .
select max(a.fid) into max_fid from test_queries a;
execute immediate 'insert into test_queries values (:1,:2) returning fid into :a' using max_fid+1,query_text,c;
What i am trying to do
I am trying to create a procedure which accepts table_name as its parameter. And inside the procedure i am dynamically dropping the table using Dynamic SQL
What is the problem
After calling the procedure by writing execute droptab('TEST'); i get the following error:
ERROR at line 1:
ORA-00950: invalid DROP option
ORA-06512: at "SYSTEM.DROPTAB", line 4
ORA-06512: at line 1
Procedure
create or replace procedure dropTab (tableName in varchar2) is
begin
EXECUTE IMMEDIATE 'DROP TABLE' || tableName;
end;
/
Change
'DROP TABLE'
to
'DROP TABLE '
I.e. add an additional space
-- Disable constaint, good
CREATE OR REPLACE PROCEDURE cpl_disable_constraint(table_name IN varchar2, constraint_name IN varchar2)
AS
BEGIN
execute immediate 'ALTER TABLE :1 DISABLE CONSTRAINT :2' using table_name, constraint_name;
END;
/
-- Bug
declare
table_name varchar2(100) := 'ADV_TEST_COURSE_CREDIT';
column_name varchar2(100) := 'SEQUENCE_NUMBER';
begin
cpl_disable_constraint(table_name, column_name);
end;
/
I'm getting these errors:
ORA-00903: invalid table name
ORA-06512: at "SISD_OWNER.CPL_DISABLE_CONSTRAINT", line 5
ORA-06512: at line 5
00000 - "invalid table name"
Any idea?
As a_horse_with_no_name mentioned, you can't pass an identifier to execute immediate as a parameter. You have to put it in the SQL statement.
execute immediate 'ALTER TABLE ' || table_name || ' DISABLE CONSTRAINT :1' using constraint_name;
Note that this will open you up to SQL Injection if you don't carefully validate the table_name variable. I usually do something like this before calling execute immediate, to make sure the table_name variable is the valid and correct table name for the constraint, and not some malicious string like null; DROP TABLE ADV_TEST_COURSE_CREDIT;:
select c.table_name into table_name from user_constraints c where c.constraint_name = constraint_name;
(By the way, this is part of why people often choose a prefix for local PL/SQL variable names, like "v_table_name", to keep them separate from column names. You can see it's a little confusing in the query above.)
Also I'd like to point out that in your function definition, you're calling the second parameter "constraint_name", but in the anonymous block you're calling it "column_name".
I am trying to run the following stored procedure:
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL;
END;
END;
/
and calling it in changelog.xml as:
<sql>CALL RETRY_TRANS_EXCEPTION();</sql>
i get error:
Liquibase update Failed: Migration failed for change set eldata-changelog.xml::2016-08-25-cn-01::Ch Will:Reason: liquibase.exception.DatabaseException: Error executing SQL CALL RETRY_TRANS_EXCEPTION(): ORA-06575: Package or function RETRY_TRANS_EXCEPTION is in an invalid state
What i am trying to achieve is to be able to run a stored procedure through Liquibase with a loop in it.
Thanks for your help Prashant. What worked in my case was your solution plus one change:
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
v_query varchar2(100);
BEGIN
FOR i IN 1..500 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
v_query := 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NULL';
execute immediate v_query;
END loop;
END;
/
and then calling the Stored Procedure from the changelog, as:
<changeSet id="2016-08-25-cw-01" author="Ch Will">
<comment>
Testing retry logic on liquibase
</comment>
<sql>CALL RETRY_TRANS_EXCEPTION();</sql>
</changeSet>
You can't call it because the procedure does not compile correctly. Go back and fix the compilation errors, then try again.
Here are a couple of errors that stand out to me:
the for loop should end with end loop;, not end;
You can't have DDL statements directly in the code. You need dynamic SQL to execute a DDL statement from a procedure: execute immediate 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL';
Additional note: I don't understand why you are trying to execute the same DDL statement multiple times inside a loop. Obviously, you won't be able to add the same column with the same name over and over. You will get a runtime error.
SQL> CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
2 AS
3 BEGIN
4 FOR i IN 1..5 LOOP
5 DBMS_OUTPUT.PUT('Try #' || i);
6 ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL;
7 END;
8 END;
9 /
Warning: Procedure created with compilation errors
SQL> show err
Errors for PROCEDURE PRASHANT-MISHRA.RETRY_TRANS_EXCEPTION:
LINE/COL ERROR
-------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6/4 PLS-00103: Encountered the symbol "ALTER" when expecting one of the following: ( begin case declare end exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Did required fixes :
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
v_query varchar2(100);
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
v_query := 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL' ;
execute immediate v_query;
END loop;
END;
PLSQL stored procedure can't use DDL statements, like
alter table ...
so the
execute immediate ("...")
statement is required because in fact it creates an autonomous implicit transition that can't be rollbacked
I'm trying to create a table and then insert some values in it within the same procedure in pl/sql. I tried to run the following query without success:
create or replace Procedure insertval8(id_no in number,e_name in char)
is
begin
execute immediate 'create table edu2(id number(20), name char(12))';
insert into edu2 values(&id_no,&e_name);
end;
displays
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PL/SQL: SQL Statement ignored
5/13 PL/SQL: ORA-00942: table or view does not exists
The error persists until I remove the insert code.
The procedure cannot be compiled because the table is not present at compile time.
Wrap the insert in execute immediate also, or use a global temporary table (generaly the preferred solution for temporary data).
create or replace procedure insertval8 (id in number,
name in char )
is
begin
execute immediate 'create table edu2(id number(20), name char(12))';
execute immediate 'insert into edu2(id, name) values (:1, :2)'
using id, name;
end;