Oracle: Using EXECUTE IMMEDIATE with RETURNING INTO - oracle

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;

Related

ORA-00922: missing or invalid option when trying to create column in table

I'm using the following code for create a column in an existing table, but, I'm getting this error:
ORA-00922: missing or invalid option
I've tried get the desired result (create column in table "only if this column does not exists") without the EXECUTE IMMEDIATE instruction, but, PL/SQL doesn't allow use the ALTER TABLE [...] in an IF [] THEN structure.
Is there something I'm missing?
This is the db<>fiddle sample:
CREATE TABLE "TMP_TABLE_SAMPLE"
( "ID_TABLE" NUMBER(9,0)
) ;
✓
SET SERVEROUTPUT ON;
CLEAR SCREEN;
DECLARE
V_COLUMN_EXISTS NUMBER := 0;
BEGIN
SELECT COUNT(1) CONTEO
INTO V_COLUMN_EXISTS
FROM USER_TAB_COLS
WHERE UPPER(COLUMN_NAME) = 'PNT_NCODE'
AND UPPER(TABLE_NAME) = 'TMP_TABLE_SAMPLE';
IF V_COLUMN_EXISTS = 0 THEN
EXECUTE IMMEDIATE 'ALTER TABLE TMP_TABLE_SAMPLE ADD PNT_NCODE NUMBER (9,0) ' ||
' COMMENT ON COLUMN TMP_TABLE_SAMPLE.PNT_NCODE IS ''Stores ID from TMP_TABLE_SAMPLE_2.''';
ELSE
DBMS_OUTPUT.PUT_LINE('Column already exists');
END IF;
END;
ORA-00922: missing or invalid option
The error you're getting is because you have set serveroutput on and clear screen in your script. db<>fiddle knows how to interpret SQL and PL/SQL. It doesn't support SQL*Plus commands.
If you remove those, the next error you'll get is that you have a single execute immediate statement that is trying to execute two separate statements. Creating the column and adding a comment on the column are separate operations so you need separate statements.
If I change your fiddle to this, it works the way you want
DECLARE
V_COLUMN_EXISTS NUMBER := 0;
BEGIN
SELECT COUNT(1) CONTEO
INTO V_COLUMN_EXISTS
FROM USER_TAB_COLS
WHERE UPPER(COLUMN_NAME) = 'PNT_NCODE'
AND UPPER(TABLE_NAME) = 'TMP_TABLE_SAMPLE';
IF V_COLUMN_EXISTS = 0 THEN
EXECUTE IMMEDIATE 'ALTER TABLE TMP_TABLE_SAMPLE ADD PNT_NCODE NUMBER (9,0) ';
EXECUTE IMMEDIATE 'COMMENT ON COLUMN TMP_TABLE_SAMPLE.PNT_NCODE IS ''Stores ID from TMP_TABLE_SAMPLE_2.''';
ELSE
DBMS_OUTPUT.PUT_LINE('Column already exists');
END IF;
END;
/

Invalid table name error, when execute alter stored procedure in oracle

-- 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".

ORA-00903:invalid table name

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;

Displaying command entered to run the trigger

I am trying to figure out how to display the insert statement, which the user enters. I want it to display after the "Please update the insert statement" text prints. From reading a ton of things online, I found out that you can display the previous command entered on oracle, by entering a "/" sign, and also by running this query 'SELECT * FROM gv$sql WHERE SQL_ID = IDENT_CURRENT('gv$sql')'. I tried using an execute immediately statement in the trigger, using dbms_output.put_line(/), and simply using t0_char('/'); in the query as you see below. Any tips?
set serveroutput on
CREATE or REPLACE trigger before_insert_t
before insert on reservations
for each row
DECLARE
rooms_remaining number(5,2);
BEGIN
select roooms_rem into rooms_remaining from reservations where roomno=:new.roomno;
if rooms_remaining = 0 then
dbms_output.put_line('Insertion now allowed because room ' || :new.roomno || ' is booked!' );
dbms_output.put_line('Please update the insert statement');
-- to_char('/');
dbms_output.put_line('insert into reservations values ' || :new.roomno );
-- EXECUTE IMMEDIATE sql_stmt;
end if;
END;
/
show errors
insert into reservations values (99,9);
CREATE or REPLACE trigger before_insert_t
before insert on TEST_TAB1
for each row
DECLARE
sql_insert varchar2(1000);
BEGIN
select sql_text into sql_insert
from (select sql_text
from v$sql
where upper(sql_text) like 'INSERT INTO TEST_TAB1%'
order by first_load_time desc)
where rownum=1;
dbms_output.put_line('Inserting into table SQL is '||sql_insert);
END;
/
SQL> set serveroutput on
SQL> insert into TEST_TAB1 values ('Hello');
1 rows inserted.
Inserting into table SQL is insert into TEST_TAB1 values (:"SYS_B_0")
You order by FIRST_LOAD_TIME and sort it in descending order and select the first row which would be the most recent INSERT statement in case there are multiple INSERTs.

how to declare SQLCA.SQLERRD?

I am trying to insert records into a table using insert....select...stmt in a oracle stored procedure. How do find the number of records inserted using SQLERRD?
recIn number;
Insert into t1 ....Select.....;
recIn := SQLCA.SQLERRD(3);
....
....
PLS-00201: identifier 'SQLCA.SQLERRD' must be declared
is the error message thrown. How do you declare SQLCA.SQLERRD?
using Oracle 9.2
bcs
Are you using PL/SQL? Or are you using Pro*C/C++? SQLCA.SQLERRD would be defined in Pro*C/C++, it would not be defined in PL/SQL. Since you didn't tag the question for Pro*C, I'm guessing that you're just using PL/SQL.
In PL/SQL, you simply reference SQL%ROWCOUNT after running a SQL statement to get the row count. Something like
DECLARE
l_num_rows INTEGER;
BEGIN
INSERT INTO t1( <<list of columns>> )
SELECT <<list of columns>>
FROM <<some tables>>
WHERE <<some predicates>>
l_num_rows := sql%rowcount;
dbms_output.put_line( 'The statement inserted ' || l_num_rows || ' rows.';
END;

Resources