Stored procedure with select count(*) and use count in IF statement - oracle

I am creating a stored procedure in Oracle database that's resulting in error "ORA-01858: a non-numeric character was found where a numeric was expected".
My procedure is as below:
create or replace procedure testProc(
id IN VARCHAR2,
user IN VARCHAR2,
sender IN VARCHAR2
)
as
vCount number;
begin
select count(*) into vCount from table1 where id='12345'
if vCount=0
insert into table1 (id, user, sender, status) values (id, user, partner, status);
else
update table1 set status='ERR' where id='12345'
end if;
end procedure;
Error: ORA-01858: a non-numeric character was found where a numeric was expected
I tried replacing vCount as int that did not help. Also tried declaring vCount below sender IN VARCHAR2.
Can someone please tell what is correct way to use the above procedure.

Use a MERGE statement then you can do it in a single statement (rather than SELECT followed by either INSERT or UPDATE):
CREATE PROCEDURE testProc(
i_id IN table1.id%TYPE,
i_user IN table1."USER"%TYPE,
i_sender IN table1.sender%TYPE,
i_status IN table1.status%TYPE
)
AS
BEGIN
MERGE INTO table1 dst
USING (
SELECT '12345' AS id
FROM DUAL
) src
ON (src.id = dst.id)
WHEN MATCHED THEN
UPDATE SET status = 'Err'
WHEN NOT MATCHED THEN
INSERT (id, "USER", sender, status)
VALUES (i_id, i_user, i_sender, i_status);
END testProc;
/
db<>fiddle here

This code can't possibly return error you specified because
procedure is invalid (mising statement terminators; column name can't be USER because it is a keyword, reserved for currently logged user)
that error code is related to date issues, while - in your code - there's nothing that looks like a date
Therefore, it is impossible to help you with error you stated. Otherwise, consider NOT naming procedure's parameters the same as column names because that leads to various problems.
Something like this would work, but it is not related to error you got.
Sample table:
SQL> CREATE TABLE table1
2 (
3 id VARCHAR2 (5),
4 c_user VARCHAR2 (20),
5 partner VARCHAR2 (10),
6 sender VARCHAR2 (10),
7 status VARCHAR2 (5)
8 );
Table created.
SQL>
Procedure:
SQL> CREATE OR REPLACE PROCEDURE testProc (p_id IN VARCHAR2,
2 p_user IN VARCHAR2,
3 p_sender IN VARCHAR2)
4 AS
5 vCount NUMBER;
6 BEGIN
7 SELECT COUNT (*)
8 INTO vCount
9 FROM table1
10 WHERE id = p_id;
11
12 IF vCount = 0
13 THEN
14 INSERT INTO table1 (id,
15 c_user,
16 sender,
17 status)
18 VALUES (p_id,
19 p_user,
20 NULL,
21 'NEW');
22 ELSE
23 UPDATE table1
24 SET status = 'ERR'
25 WHERE id = p_id;
26 END IF;
27 END testproc;
28 /
Procedure created.
Testing:
SQL> EXEC testproc('12345', 'Little', 'Foot');
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table1;
ID C_USER PARTNER SENDER STATU
----- -------------------- ---------- ---------- -----
12345 Little NEW
SQL> EXEC testproc('12345', 'Little', 'Foot');
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table1;
ID C_USER PARTNER SENDER STATU
----- -------------------- ---------- ---------- -----
12345 Little ERR
SQL>

Related

Getting the SQL ID's of each statement executed in a stored procedure

I have the following Stored Procedure:
create or replace procedure insert_employee_to_dept (f_name IN varchar2, l_name IN varchar2, dept IN varchar2, tier IN char)
is
dept_count number;
t1_count number;
begin
INSERT INTO employees (id, first_name, last_name, department, tier)
VALUES (employee_sequence.NEXTVAL,
f_name,
l_name,
dept,
tier);
select count(*) into dept_count from employees where department = dept;
update dept_info set emp_count = dept_count where id = dept;
select count(*) into t1_count from employees where tier = 1;
update company set tier_one_count = t1_count where name = 'MyCompany';
end;
I enable SQL ID feedback using below statement
set feedback on sql_id;
Finally I run my Stored Procedure as such:
call insert_employee_to_dept('John', 'Doe', 'Finance', '5')
The output of the above command contains the SQL id of the PL/SQL block but this block does not have an execution block which can be queried using DBMS_XPLAN.DISPLAY_CURSOR
Is there a way to get all the SQL ID's that were executed when the stored procedure was called?
Following this answer, I enabled tracing and ran the procedure which generated the trace file on the server. Unfortunately in my use case I do not have access the file system of the database server
You may use all_statements system view to get all the statements executed in PL/SQL unit and their SQL_ID's.
create table t (
id int,
val int
)
/
create or replace procedure test_proc(
p_id in int
)
as
begin
insert into t(id, val) values(p_id, 100);
update t set val = 10;
delete from t where id = p_id;
end;
/
begin
test_proc(1);
end;
/
select
owner
, object_type
, object_name
, type
, line
, sql_id
, text
from all_statements
/
OWNER
OBJECT_TYPE
OBJECT_NAME
TYPE
LINE
SQL_ID
TEXT
DEMO
PROCEDURE
TEST_PROC
DELETE
8
85cd3d95cya5x
DELETE FROM T WHERE ID = :B1
DEMO
PROCEDURE
TEST_PROC
UPDATE
7
d6au94gzv1ydh
UPDATE T SET VAL = 10
DEMO
PROCEDURE
TEST_PROC
INSERT
6
bm74chwppp8w4
INSERT INTO T(ID, VAL) VALUES(:B1 , 100)
If you doing that for testing purpose, you can use dbms_application_info to set module and action, and then use them to select from v$sql/v$sqlarea/v$active_session_history/etc:
SQL> declare
2 n number;
3 begin
4 dbms_application_info.set_module('test_module','test_action');
5 select/*+test1*/ count(*) into n from dual;
6 select/*+test2*/ count(*) into n from dual;
7 dbms_application_info.set_module('','');
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select sql_id,substr(sql_text,1,50) sqltext50
2 from v$sqlarea
3 where module='test_module'
4 and action='test_action';
SQL_ID SQLTEXT50
------------- ------------------------------------
bavxnddfrxju6 SELECT/*+test2*/ COUNT(*) FROM DUAL
7d8853usybzdg SELECT/*+test1*/ COUNT(*) FROM DUAL
Btw, you can use module/action/client_id also for dbms_monitor:
Performing Application Tracing
DBMS_MONITOR
Or sometimes you can even use v$open_cursor (depends on many factors like open_cursor parameter, etc):
SQL> declare
2 n number;
3 begin
4 dbms_application_info.set_module('test_module','test_action');
5 select/*+test10*/ count(*) into n from dual;
6 select/*+test11*/ count(*) into n from dual;
7 dbms_application_info.set_module('','');
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select sql_id,substr(sql_text,1,50) sqltext50
2 from v$open_cursor
3 where sid=userenv('sid')
4 and user_name=user
5 and last_sql_active_time is not null
6 order by last_sql_active_time desc
7 fetch first 5 rows only;
SQL_ID SQLTEXT50
------------- ---------------------------------------------------
3669hp0tndbgu declare n number; begin dbms_application_inf
9szagfb62bhgs SELECT/*+test10*/ COUNT(*) FROM DUAL
9h8pabdtrb1wm select sql_id,substr(sql_text,1,50) sqltext50 from
1901dfp1ktg5d SELECT/*+test11*/ COUNT(*) FROM DUAL
bavxnddfrxju6 SELECT/*+test2*/ COUNT(*) FROM DUAL

In Oracle SQL, I would like to call a Oracle stored procedure and then select the value of an OUT parameter as a column result. Is this possible?

CREATE OR REPLACE PROCEDURE myStoredProcedure (idParam IN VARCHAR2,
outputParam OUT VARCHAR2)
AS
BEGIN
SELECT OUTPUTCOL INTO outputParam FROM MyTable WHERE ID = idParam;
END;
DECLARE
v_OutputResults VARCHAR2(20);
BEGIN
myStoredProcedure('123', v_OutputResults);
SELECT v_OutputResults AS ColumnResult FROM DUAL;
END;
If we understand your goal, you should be using a function, not a procedure:
First, we set up the example:
SQL> -- conn system/halftrack#pdb01
SQL> conn scott/tiger#pdb01
Connected.
SQL> --
SQL> CREATE TABLE my_table (
2 user_id number not null,
3 Name varchar2(10)
4 )
5 ;
Table created.
SQL> --
SQL> insert into my_table values (1,'Bob');
1 row created.
SQL> insert into my_table values (2,'Carol');
1 row created.
SQL> insert into my_table values (3,'Ted');
1 row created.
SQL> insert into my_table values (4,'Alice');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from my_table;
USER_ID NAME
---------- ----------
1 Bob
2 Carol
3 Ted
4 Alice
4 rows selected.
Now we create the function, then use it:
SQL> --
SQL> create or replace function my_function (id_param number)
2 return varchar2
3 is
4 v_name varchar2(10);
5 begin
6 select name
7 into v_name
8 from my_table
9 where user_id = id_param
10 ;
11 --
12 return v_name;
13 end;
14 /
Function created.
SQL> show errors
No errors.
SQL> --
SQL> select my_function(1) from dual;
MY_FUNCTION(1)
--------------------------------------------------------------------------------
Bob
1 row selected.
And clean up our example:
SQL> --
SQL> drop table my_table purge;
Table dropped.
No but you can do so using a stored function.

SQL Developer ERROR: Reference to uninitialized collection

I am executing the below procedure from SQL DEVELPER, I get an option to insert the input values for z_id & i_type however i_data is greyed out.
can a procedure with input param as collection cannot be executed from SQL
DEVELOPER tool ?
What am I missing here ? The code gets compiled but unable to execute it through SQL Developer
below is what I have done but this gives compilation error on Oracle 19c
create or replace type my_type AS OBJECT (
p_id number,
p_text varchar2 (100),
p_details clob);
/
create or replace type tab1 is table of my_type;
/
create or replace procedure vehicle_det (z_id in varchar2, i_type in varchar2, i_data in tab1)
IS
BEGIN
for i in 1..i_data.count
LOOP
if (i_type ='BMW')
THEN
UPDATE STOCK_DATA
set stock_id=i_data(i).p_id, stock_des=i_data(i).p_text, clearance=i_data(i).p_details where s_id=z_id ;
end if;
end loop;
end vehicle_det;
Below is the error, please provide your wisdom::::
**ERROR --ORA-06531 Reference to uninitialized collection **
Here's code that actually works. See how it is done.
Types and sample table:
SQL> create or replace type my_type AS OBJECT (
2 p_id number,
3 p_text varchar2 (100),
4 p_details clob);
5 /
Type created.
SQL> create or replace type tab1 is table of my_type;
2 /
Type created.
SQL> create table stock_data
2 (s_id number,
3 stock_id number,
4 stock_des varchar2(20),
5 clearance clob);
Table created.
SQL> insert into stock_data
2 select 1 s_id, 1 stock_id, 'Description' stock_Des, null clearance
3 from dual;
1 row created.
SQL>
Procedure:
SQL> create or replace procedure vehicle_det
2 (z_id in varchar2, i_type in varchar2, i_data in tab1)
3 IS
4 BEGIN
5 for i in 1..i_data.count LOOP
6 if i_type = 'BMW' THEN
7 UPDATE STOCK_DATA
8 set stock_id = i_data(i).p_id,
9 stock_des = i_data(i).p_text,
10 clearance = i_data(i).p_details
11 where s_id = z_id ;
12 end if;
13 end loop;
14 end vehicle_det;
15 /
Procedure created.
Testing: current table contents / run the procedure / see the result:
SQL> select * from stock_data;
S_ID STOCK_ID STOCK_DES CLEARANCE
---------- ---------- -------------------- ------------------------------
1 1 Description
SQL> declare
2 l_data tab1 := tab1();
3 begin
4 l_data.extend;
5 l_data(1) := my_type(1, 'This is BMW', 'Oh yes, this IS a BMW!');
6
7 vehicle_det(1, 'BMW', l_data);
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select * from stock_data;
S_ID STOCK_ID STOCK_DES CLEARANCE
---------- ---------- -------------------- ------------------------------
1 1 This is BMW Oh yes, this IS a BMW!
SQL>

Procedure to insert details by raising exceptions in PL/SQL

I want to create a procedure to insert employee details into Employee table. Before inserting, check whether the employee age is eligible or not. Employee age should be 18 or greater. Values are passed as argument to the procedure. If age valid, insert employee record into table and print the message "Age valid - Record inserted", else print the message "Age invalid - Record not inserted" by raising an exception.
Table: EMPLOYEE
Column name Data type Constraints
EMP_ID NUMBER(5) PK
EMP_NAME VARCHAR2(25) NOT NULL
AGE NUMBER(3)
Functional Requirement:
PROCEDURE CHECK_AGE_ELIGIBILITY(
v_id IN EMPLOYEE.EMPID%TYPE,
v_name IN EMPLOYEE.EMPNAME%TYPE,
v_age IN EMPLOYEE.AGE%TYPE)
I have written a code for this as-
set serveroutput on;
create or replace procedure check_age_eligibility(
v_id in employee.empid%type,
v_name in employee.empname%type,
v_age in employee.age%type)
is emp_rec employee%rowtype;
declare
Employee_age number;
BEGIN
SELECT trunc(MONTHS_BETWEEN(TO_DATE(sysdate,'DD-MON-YYYY'), TO_DATE(:new.DATE_OF_BIRTH,'DD-MON-YYYY'))/12)
INTO Employee_age FROM DUAL;
IF (Employee_age >= 18) THEN
update employee;
dbms_output.put_line('Age valid - Record inserted');
else
dbms_output.put_line('Age invalid - Record not inserted');
END IF;
end;
/
Please check for any errors since my code editor is not showing any output for this code. Thanks in advance!
You're overcomplicating it. There's no "date of birth" there; you're working with age (presumably expressed in years).
So: procedure:
SQL> create or replace procedure check_age_eligibility
2 (par_id in employee.emp_id%type,
3 par_emp_name in employee.emp_name%type,
4 par_age in employee.age%type
5 )
6 is
7 begin
8 if par_age >= 18 then
9 insert into employee (emp_id, emp_name, age)
10 values
11 (par_id, par_emp_name, par_age);
12
13 dbms_output.put_line('Age valid - record inserted');
14 else
15 raise_application_error(-20000, 'Age invalid - record not inserted');
16 end if;
17 end;
18 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec check_age_eligibility(1, 'Little', 12);
BEGIN check_age_eligibility(1, 'Little', 12); END;
*
ERROR at line 1:
ORA-20000: Age invalid - record not inserted
ORA-06512: at "SCOTT.CHECK_AGE_ELIGIBILITY", line 15
ORA-06512: at line 1
SQL> exec check_age_eligibility(1, 'Foot' , 20);
Age valid - record inserted
PL/SQL procedure successfully completed.
SQL> select * From employee;
EMP_ID EMP_NAME AGE
---------- -------------------- ----------
1 Foot 20
SQL>

fetching table data into a table using cursor

I have a table called phonebook and it has two columns (firstName, LastName). I want to create a table of lastName index by firstName using cursor, and I wrote this code:
CREATE OR REPLACE PROCEDURE proc1 AS
TYPE tableNames IS TABLE OF VARCHAR2(20) INDEX BY VARCHAR(20);
v1 tableNames;
v_firstName PHONEBOOK.FIRSTNAME%TYPE;
v_lastName PHONEBOOK.LASTNAME%TYPE;
CURSOR c_name IS SELECT FIRSTNAME, LASTNAME FROM PHONEBOOK;
BEGIN
OPEN c_name;
LOOP
FETCH c_name INTO v_firstName, v_lastName;
EXIT WHEN c_name%NOTFOUND;
v1(v_firstName) := v_lastName;
END LOOP;
FOR idx IN v1.FIRST..v1.LAST
LOOP
DBMS_OUTPUT.PUT_LINE (v1(idx));
END LOOP;
CLOSE c_name;
END;
/
It has been successfully compiled. When I run this procedure it should print lastNames which stored in the tableNames but it gave me an error:
ORA-06502 "PL/SQL: numeric or value error"
Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
Please help me to solve this problem
Not FOR, but WHILE. Also, I used cursor FOR loop as a source; easier to write & maintain.
SQL> create table phonebook (firstname varchar2(10), lastname varchar2(10));
Table created.
SQL> insert into phonebook
2 select 'Little', 'Foot' from dual union all
3 select 'Mc' , 'Donalds' from dual;
2 rows created.
SQL> create or replace procedure proc1 as
2 type tablenames is table of varchar2(10) index by varchar2(10);
3 v1 tablenames;
4 idx varchar2(10);
5 begin
6 for cur_r in (select firstname, lastname
7 from phonebook
8 )
9 loop
10 v1(cur_r.firstname) := cur_r.lastname;
11 end loop;
12
13 idx := v1.first;
14 while idx is not null loop
15 dbms_output.put_line(v1(idx));
16 idx := v1.next(idx);
17 end loop;
18 end;
19 /
Procedure created.
SQL> exec proc1;
Foot
Donalds
PL/SQL procedure successfully completed.
SQL>

Resources