Capture error using OUT parameter in Oracle's procedure - oracle

I have to create procedure to insert row into table, also I need to include am OUT parameter that would capture any errors. However when I test using anonymous block it would not work, but if I use exception in procedure it is working. It means if I add an OUT parameter and I pass values from the block it won't work.
This code works but is not what I want:
create or replace
PROCEDURE EXAM_SP
(P_FIRSTNAME IN BB_SHOPPER.FIRSTNAME%TYPE,
P_LASTNAME IN BB_SHOPPER.LASTNAME%TYPE,
P_ADDRESS IN BB_SHOPPER.ADDRESS%TYPE,
P_CITY IN BB_SHOPPER.CITY%TYPE,
P_STATE IN BB_SHOPPER.STATE%TYPE,
P_ZIP IN BB_SHOPPER.ZIPCODE%TYPE)
IS
BEGIN
INSERT INTO BB_SHOPPER (IDSHOPPER, FIRSTNAME, LASTNAME, ADDRESS, CITY,
STATE, ZIPCODE)
VALUES
(BB_SHOPPER_IDSHOPPER_SEQ.NEXTVAL,P_FIRSTNAME,P_LASTNAME,P_ADDRESS,
P_CITY, P_STATE,P_ZIP);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error Code = '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Error Message = Please check input');
END EXAM_SP;.
But in code above if I name out parameter it won't work, not sure how to do this, if I add OUT parameter to procedure and pass values:
create or replace
PROCEDURE EXAM_SP
(P_FIRSTNAME IN VARCHAR2,
P_LASTNAME IN VARCHAR2,
P_ADDRESS IN VARCHAR2,
P_CITY IN VARCHAR2,
P_STATE IN CHAR,
P_ZIP IN VARCHAR2,
P_ERROR OUT VARCHAR2)......
I will receive this error
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
If I remove parameter and use original code on the beginning it works.
Anonymous block that gets that error:
DECLARE
LV_FIRSTNAME_TXT BB_SHOPPER.FIRSTNAME%TYPE := 'FIRST';
LV_LASTNAME_TXT BB_SHOPPER.LASTNAME%TYPE := 'LAST';
LV_ADDRESS_TXT BB_SHOPPER.ADDRESS%TYPE := '8899 TAPE PARK';
LV_CITY_TXT BB_SHOPPER.CITY%TYPE := 'JACKSONVILLE';
LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd';
LV_ZIP_NUMBER BB_SHOPPER.ZIPCODE%TYPE := '34567';
LV_ERROR varchar2(100);
BEGIN
EXAM_SP(LV_FIRSTNAME_TXT, LV_LASTNAME_TXT, LV_ADDRESS_TXT,
LV_CITY_TXT,LV_STATE_TXT,LV_ZIP_NUMBER);
DBMS_OUTPUT.PUT_LINE(LV_ERROR);
END;
Procedure:
create or replace
PROCEDURE EXAM_SP
(P_FIRSTNAME IN VARCHAR2,
P_LASTNAME IN VARCHAR2,
P_ADDRESS IN VARCHAR2,
P_CITY IN VARCHAR2,
P_STATE IN CHAR,
P_ZIP IN VARCHAR2,
P_ERROR OUT VARCHAR2)
IS
BEGIN
INSERT INTO BB_SHOPPER (IDSHOPPER, FIRSTNAME, LASTNAME, ADDRESS, CITY,
STATE, ZIPCODE)
VALUES
(BB_SHOPPER_IDSHOPPER_SEQ.NEXTVAL,P_FIRSTNAME,P_LASTNAME,P_ADDRESS,
P_CITY, P_STATE,P_ZIP);
EXCEPTION
WHEN OTHERS THEN
P_ERROR := SQLCODE;
/*DBMS_OUTPUT.PUT_LINE('Error Code = '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Error Message = Please check input');
P_ERROR := SQLCODE;*/
END EXAM_SP;
Error message that I am receiving:
Error report:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
06502. 00000 - "PL/SQL: numeric or value error%s"
I have passed variable 'FLd' to procedure parameter in order to test error capture.
Table structure:
IDSHOPPER NUMBER(4,0)
FIRSTNAME VARCHAR2(15 BYTE)
LASTNAME VARCHAR2(20 BYTE)
ADDRESS VARCHAR2(40 BYTE)
CITY VARCHAR2(20 BYTE)
STATE CHAR(2 BYTE)
ZIPCODE VARCHAR2(15 BYTE)
PHONE VARCHAR2(10 BYTE)
FAX VARCHAR2(10 BYTE)
EMAIL VARCHAR2(25 BYTE)
USERNAME VARCHAR2(8 BYTE)
PASSWORD VARCHAR2(8 BYTE)
COOKIE NUMBER(4,0)
DTENTERED DATE
PROVINCE VARCHAR2(15 BYTE)
COUNTRY VARCHAR2(15 BYTE)
...

"If I add out parameter to procedure and I pass values I will receive this error"
Alex has provided the long answer, I'm just going to make one short point: this is bad practice. Most programming languages include built-in functionality for handling exceptions. What you propose creates two architectural problems:
Programs which call your procedure have to write non-standard code to catch errors, which is just a pain for both the developers who write the calling programs and everybody else who has to understand how they work.
Your procedure doesn't hurl an exception so even though it "failed" it returns a success state to calling programs. If the developer who wrote the calling program didn't implement the special code the exception is lost and the database can be left in an invalid state.

The error stack shows:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
06502. 00000 - "PL/SQL: numeric or value error%s"
That stack shows, partly because it doesn't mention the procedure name, that the error is from line 6 of the anonymous block. It isn't getting as far as the call to the procedure on line 11 of that block.
The problem is that you've defined the local state variable:
LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd';
using the %TYPE syntax, which is great; but as the table column is char(2), when you try to assign the three-character text literal 'Fld' to that two-character local variable it immediately errors at that point.
it is not getting as far as sending the three-character value to the procedure, so the error you're expecting from the insert doesn't appear because the insert doesn't happen either.
If you want to break it with that particular error you can either change the local variable declaration to be a fixed length instead of using %TYPE as you would normally want to:
DECLARE
LV_FIRSTNAME_TXT BB_SHOPPER.FIRSTNAME%TYPE := 'FIRST';
LV_LASTNAME_TXT BB_SHOPPER.LASTNAME%TYPE := 'LAST';
LV_ADDRESS_TXT BB_SHOPPER.ADDRESS%TYPE := '8899 TAPE PARK';
LV_CITY_TXT BB_SHOPPER.CITY%TYPE := 'JACKSONVILLE';
--LV_STATE_TXT BB_SHOPPER.STATE%TYPE := 'FLd';
-- specific length to allow invalid value to be used
LV_STATE_TXT char(3) := 'FLd';
LV_ZIP_NUMBER BB_SHOPPER.ZIPCODE%TYPE := '34567';
LV_ERROR varchar2(100);
BEGIN
EXAM_SP(LV_FIRSTNAME_TXT, LV_LASTNAME_TXT, LV_ADDRESS_TXT,
LV_CITY_TXT,LV_STATE_TXT,LV_ZIP_NUMBER,LV_ERROR);
DBMS_OUTPUT.PUT_LINE(LV_ERROR);
END;
/
-12899
PL/SQL procedure successfully completed.
Or more simply use literals directly for the IN parameters, as you are just testing the procedure at this point:
DECLARE
LV_ERROR varchar2(100);
BEGIN
EXAM_SP('FIRST', 'LAST', '8899 TAPE PARK',
'JACKSONVILLE', 'FLd', '34567', LV_ERROR);
DBMS_OUTPUT.PUT_LINE(LV_ERROR);
END;
/
-12899
PL/SQL procedure successfully completed.
You might find it more useful to return the error text, not just the number (and if you're returning the error number use a numeric formal argument type!), e.g:
...
EXCEPTION
WHEN OTHERS THEN
P_ERROR := SQLERRM;
END EXAM_SP;
/
-- same anonymous block
ORA-12899: value too large for column "MY_SCHEMA"."BB_SHOPPER"."STATE" (actual: 3, maximum: 2)
PL/SQL procedure successfully completed.
Of course, as I mentioned in a comment, it's better to let Oracle's exception handling just bubble the actual exception up to the caller - aside maybe from logging, you should only really catch exceptions you can actually handle. Notice that the error message that's passed back doesn't tell you anything about where the error occurred in the code; without the exception handler you would see the line number in the procedure that had the offending statement. And as APC points out, every caller has to look for and handle the resposne, and it would be easy to overlook. There are always exceptions (ha) of course, but this seems to be an exercise in doing things wrong.

Related

How to add a new user in a PL/SQL table using a function?

I am fairly new to PL/SQL and one of the doubts I have is to create and declare functions.
Specifically this one:
Create a function that creates a new user:
Use a sequence togive the new User a new ID
Pass the name, address, etc... as IN arguments
Return as OUT arguments the ID created and a O_ERROR_MESSAGE
Function returns TRUE if the user is added, otherwise returns FALSE
Handle exceptions
Create a PL/SQL block and test the created function
This is my code so far:
CREATE OR REPLACE FUNCTION DSB_ADD_NEW_USERS (I_NAME IN VARCHAR2,
I_ADDRESS IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2)
RETURN NUMBER IS
O_ERROR_MESSAGE EXCEPTION;
CURRENT_USER NUMBER;
BEGIN
DSB_NB_SEQ_USER_ID.NEXTVAL;
SELECT COUNT(USER_ID) INTO CURRENT_USER
FROM DSB_NB_USERS;
WHILE CURRENT_USER != 0
LOOP
DSB_NB_SEQ_USER_ID.NEXTVAL;
SELECT COUNT(USER_ID) INTO CURRENT_USER
FROM DSB_NB_USERS;
END LOOP;
INSERT INTO DSB_NB_USERS (USER_ID, NAME, ADDRESS, BIRTHDATE, COUNTRY_ID_FK) VALUES (CURRENT_USER, I_NAME, I_ADDRESS, TO_DATE('I_BIRTHDATE', 'DD/MM/YYYY'), I_COUNTRY);
RETURN CURRET_USER;
EXCEPTION
WHEN O_ERROR_MESSAGE THEN
RETURN NULL;
WHEN OTHERS THEN
RETURN NULL;
END;
DECLARE
I_NEW_USER NUMBER;
BEGIN
I_NEW_USER := DSB_ADD_NEW_USERS(I_NAME => 'Arnaldo Amaral',
I_ADDRESS => 'Rua da Agra',
I_BIRTHDATE => '03/05/1959',
I_COUNTRY => 'PT');
END;
Am i too far from the truth?
I know there's still a lot to add.
Thank you for the help!!!
It seems to me you are asking for a lifeline, that needs more than just a code response. First off look at the answer by
#Tejash. His solution is a far cry from what you have, and is correct for your function definition (although that is itself incorrect given your listed requirements.) Also, #EdStevens is correct that is is a very poor use of a function. However a function is your assignment's requirement.
So lets dissect your code and see how it satisfies each of your requirements. (I cannot stand all caps, so I'm lower casing it.)
Fails. While you have a sequence it is used improperly. You can not
just code a standalone name. It must be used in either a SQL
statement or an assignment statement.
Passes.
Fails. Your function passes the IN parameters correctly. However
there are no OUT parameters.
Your function returns Number not the required True/False which
requires either Boolean or varchar2 for literal.
Code section for requirements 3,4.
create or replace function dsb_add_new_users (i_name in varchar2,
i_address in varchar2,
i_birthdate in date,
i_country in varchar2) <<< where are the 2 required out parameters
return number is <<< Should be True or False so either Boolean or varchar2
o_error_message exception; <<< Should be an Out parameter not an exception
Yes you have the Exception Section, which is required for handling
exceptions. However you do not handle exceptions so much as suppress
them, indicating to Oracle, and to the calling routine, that they didn't actually happen.
exception
when o_error_message then <<< as coded this is a developer defined exception, yet is not raised so it cannot happen.
return null; <<< even if it were raised you have thrown it away, the calling routine will never it happened
when others then <<< One of the worst pieces of code that can be written. I tend to remember seeing a discussion in
return null; <<< Oracle that would make this a compile time error. To bad the supporters lost the argument.
Passed, mostly. Correct for posted code, but insufficient per requirements.
So all-in-all not highly successful when viewed against the requirements.
A couple other items not specific the requirements, but disaster to successful implementation.
While technically you might get away with the following it is very bad practice. Current_User is an Oracle reserved word.
current_user number; <<< NO, NO bad verifiable name.
The following completely decimates your function. It creates a never ending loop. Well not quite -- it runs 1 time, but never afterward.
I believe you intended for the current_user variable to contain the ID assigned to the user. But it actually contains the number of rows in the table. Further what would the number of rows (count) have to do with Inserting a row? SO what does the code actually Do?
dsb_nb_seq_user_id.nextval; <<< systax error.
select count(user_id) into current_user <<< count the number of rows in the table
from dsb_nb_users;
while current_user != 0 <<< if there are any rows in the table
loop
dsb_nb_seq_user_id.nextval; <<< syntax error
select count(user_id) into current_user <<< try counting then again until there are none.
from dsb_nb_users;
end loop;
So correcting for the above what do we wind up with. I hesitate here in fear you will just copy the below and submit it. Please don't do that but study and understand what it's doing, then rewrite you routine. But after tearing you initial effort up, I guess I owe a corrected solution.
create or replace function dsb_add_new_users
( i_name in varchar2
, i_address in varchar2
, i_birthdate in date
, i_country in varchar2
, o_new_user_id out number
, o_error_message out varchar2
return boolean
is
country_id_l number;
begin
-- initialize out variables
o_new_user_id := null;
o_error_message := null;
-- get country id from input parameter
select country_id
into country_id_l
from country
where name = i_country;
-- create user and get the assigned user_id
insert into dsb_nb_users (user_id, name, address, birthdate, country_id_fk)
values dsb_nb_seq_user_id.nextval
, i_name
, i_address
, i_birthdate
, country_id_l
)
returning user_id
into o_new_user_id;
return true;
exception
when no_date_found then
o_output_message = 'ERROR: Specified country name ''' || country_id_l || ''' Not Found.';
return false;
when others then
o_output_message := 'ERROR: ' || sqlerrm;
return false
end dsb_add_new_users ;
--------------- Test Driver ----------------
declare
i_new_user number;
new_user_created boolean;
error_message varchar2(255);
begin
new_user_created := dsb_add_new_users( i_name => 'Arnaldo Amaral',
, i_address => 'Rua da Agra'
, i_birthdate => to_date('03/05/1959','mm/dd/yyyy') -- or is it 'dd/mm/yyyy'
, i_country => 'PT'
, o_new_user_id => i_new_user
, o_error_message => error_message);
if not new_user_created
then
dbms_output.put_line (error_messag);
end if ;
end;
Disclaimer: As you did not post table DDL nor test data the routine has not been tested nor even compiled. Any syntax error(s) is for you to resolve. Further, I follow Tejash in the assumption you actually have a countries table and there is a FK to it. That may be an erroneous assumption.
Why don't you directly use the sequence value to insert new user as follows:
CREATE OR REPLACE FUNCTION DSB_ADD_NEW_USERS (
I_NAME IN VARCHAR2,
I_ADDRESS IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2
) RETURN NUMBER IS
CURRENT_USER_ID NUMBER;
BEGIN
CURRENT_USER_ID := DSB_NB_SEQ_USER_ID.NEXTVAL; -- returns new and unique number
INSERT INTO DSB_NB_USERS (
USER_ID,
NAME,
ADDRESS,
BIRTHDATE,
COUNTRY_ID_FK
) VALUES (
CURRENT_USER_ID,
I_NAME,
I_ADDRESS,
I_BIRTHDATE,
(
SELECT
COUNTRY_ID
FROM
COUNTRIES
WHERE
NAME = I_COUNTRY
) -- it is FK so need to use SELECT sub-query to find COUNTRY_ID
);
RETURN CURRENT_USER_ID; -- returning the new user ID
EXCEPTION
WHEN OTHERS THEN
RETURN -1; -- returning -1 in case there is any error
END;
-1 will be returned when there is an error while adding the new user.
Came up with this much simpler answer after asking to a few people for help.
create or replace FUNCTION DSB_ADD_NEW_USERS (I_NAME IN VARCHAR2,
I_ADDRESS IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2)
RETURN NUMBER IS
CURRENT_USER NUMBER;
BEGIN
CURRENT_USER := DSB_NB_SEQ_USER_ID.NEXTVAL;
DBMS_OUTPUT.PUT_LINE('Hello World');
INSERT INTO DSB_NB_USERS (USER_ID, NAME, ADDRESS, BIRTHDATE, COUNTRY_ID_FK) VALUES (CURRENT_USER, I_NAME, I_ADDRESS, TO_DATE(I_BIRTHDATE, 'DD/MM/YYYY'), I_COUNTRY);
RETURN CURRENT_USER;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END;
SET SERVEROUT ON
DECLARE
I_NEW_USER NUMBER;
BEGIN
I_NEW_USER := DSB_ADD_NEW_USERS(I_NAME => 'Arnaldo Amaral',
I_ADDRESS => 'Rua da Agra',
I_BIRTHDATE => '03/MAY/1959',
I_COUNTRY => 'PT');
commit;
END;
/
Thank you all!!!

What do these errors mean and how do you suggest I fix them?

I am new to learning SQL and currently learning it in class. I am trying to write a code that fulfills the following requirements:
Make a reservation: Input parameters: Hotel, guest’s name, start date, end dates, room type, date of reservation. Output: reservation ID. NOTE: Only one guest per reservation. However, the same guest can make multiple reservations.
Find a reservation: Input is the guest’s name and date, hotel ID. The output is reservation ID
I am still somewhat new to deciphering error codes and tried to look up what they mean. However, I'm still not quite sure why my code is wrong.
CREATE OR REPLACE PACKAGE hotelmanagement AS
FUNCTION make(rsrv_id VARCHAR2
,hotel_name VARCHAR2
,guest VARCHAR2
,start_date VARCHAR2
,end_date VARCHAR2
,room_type VARCHAR2
,rsrv_date VARCHAR2)
RETURN NUMBER IS
rsrv_id NUMBER;
BEGIN
SELECT rsrv_seq.nextval INTO reserve_id FROM dual;
INSERT INTO reservations
VALUES
(reserve_id, 'Four Seasons', 'Amanda', 'July-30-2019', 'Aug-8-2019',
'King', 'July-18-2019');
tot_rsrv := tot_rsrv + 1;
RETURN(rsrv_id);
END;
FUNCTION find(guest VARCHAR2
,rsrv_date VARCHAR2)
RETURN NUMBER IS
rsrv_id NUMBER;
BEGIN
SELECT rsrv_id
INTO guest
FROM reservations
WHERE rsrv_date = find_rsrv_date;
END;
RETURN(rsrv_id);
END hotelmanagement;
I have these error messages(two of them look the same?):
Error(4,1): PLS-00103: Encountered the symbol "SELECT" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior The symbol "begin" was substituted for "SELECT" to continue.
Error(5,1): PLS-00103: Encountered the symbol "RSRV_ID" when expecting one of the following: language
Error(5,1): PLS-00103: Encountered the symbol "RSRV_ID" when expecting one of the following: language
The requirements are a quite vague, so it is difficult to provide the desired procedure. Anyway, your code has some weak items.
Your procedure has several input parameters but you don't use them inside the procedure.
Use appropriate data types, i.e. never(!) store DATE or number values in string, i.e. VARCHAR2. Use VARCHAR2 only for string data. At least you use four digit year, which is the proper way of doing it.
RETURN command does not use brackets.
Taking all this into account your code should be more or less like this:
CREATE OR REPLACE PACKAGE BODY hotelmanagement AS
FUNCTION make( -- you can't declare variable "rsrv_id" twice
hotel_name IN VARCHAR2
,guest IN VARCHAR2
,start_date IN DATE
,end_date IN DATE
,room_type IN VARCHAR2
,rsrv_date IN DATE)
RETURN NUMBER IS
rsrv_id NUMBER;
BEGIN
INSERT INTO reservations
VALUES
(rsrv_seq.nextval, hotel_name, guest, start_date, end_date,
room_type, rsrv_date)
RETURNING reserve_id INTO rsrv_id ;
-- tot_rsrv := tot_rsrv + 1; -> I don't see any use for it, variable tot_rsrv is not declared
RETURN rsrv_id;
END;
FUNCTION find(v_guest IN VARCHAR2
,rsrv_date IN DATE) RETURN NUMBER IS
rsrv_id NUMBER;
BEGIN
SELECT rsrv_id
INTO rsrv_id
FROM reservations
WHERE rsrv_date = find_rsrv_date
and guest = v_guest; -- don't use "guest = guest" because this will select all rows.
RETURN rsrv_id;
END;
END hotelmanagement;

Compile Error for Oracle Procedure

I have the following PL/SQL code in a script and am trying to run it in SQL*Plus:
create or replace procedure add_employee
(fname IN varchar2(20), lname IN varchar2(25), email IN varchar2(25), job IN varchar2(25))
AS
eid INTEGER := 300;
BEGIN
insert into Employees (employee_id, first_name, last_name, email, hire_date, job_id)
values (eid, fname, lname, email, job);
END add_employee;
/
I get the following error:
Errors for PROCEDURE ADD_EMPLOYEE:
LINE/COL
---------------------------------------------------------------------------
ERROR
---------------------------------------------------------------------------
1/42
PLS-00103: Encountered the symbol "(" when expecting one of the following:
:= . ) , # % default character
The symbol ":=" was substituted for "(" to continue.
I don't understand what the issue is. I have written other procedures where the opening parenthesis follows the procedure name without any problem.
You can't specify the size of strings in the procedure declaration, so it should be:
create or replace procedure add_employee
(fname IN varchar2, lname IN varchar2, email IN varchar2, job IN varchar2)
It's not a good idea to have the argument names match any table columns (email and job in this case); prefixing the parameters is common, e.g. using p_email and p_job; but should be done consistently. It often also makes it easier to follow the code even when the names don't clash - you know where the variable comes from and what its scope is.

PLS-00306: wrong number or types of arguments in call

I've got the following procedure to insert a user into a database. I use 4 in-parameters and 1 out-parameter. The out-parameter is filled with a sequence.
The table structure is a user_id and the names of the 4 first parameters.
CREATE OR REPLACE PROCEDURE insert_user
(
P_USERNAME IN varchar2,
P_PASSWORD IN varchar2,
P_COMPANY_EMAIL IN varchar2,
P_EMPLOYEE_ID IN number,
P_USER_ID OUT int)
AS
BEGIN
INSERT INTO system_users.users(USERNAME, PASSWORD, COMPANY_EMAIL, EMP_ID)
VALUES
(P_USERNAME, P_PASSWORD, P_COMPANY_EMAIL, P_EMPLOYEE_ID);
dbms_output.put_line (P_USER_ID);
END;
I get the error that I have the wrong number or types of arguments when I call the procedure. I called it like so:
insert_user('user', 'password', 'mail#mail.com', '5');
I have tried calling it with begin and end around it, I have tried the number without quotes, all wiithout quotes.
What am I doing wrong? Can it have something to do with the trigger not filling the user_id?
Regards,
Vincent
EDIT: JIC it is the trigger, here is the code for the trigger. It worked, but I saw a snag in the code so I edited it. FSR it says that the table I am trying to find (system_users.users) does not exist (invalid identfier)
PLEASE PLEASE help me!
create or replace trigger user_trig_bi
Before insert on system_users.users
for each row
begin
select user_seq.nextval
into new.user_ID
From dual
where exists (SELECT emp_id
from hrm_repo.employees
where hrm_repo.employees.emp_id = system_users.users.emp_id);
END;
The error I get is:
Error(7,55): PL/SQL: ORA-00904: "SYSTEM_USERS"."USERS"."EMP_ID": invalid identifier
Since your procedure has an out variable, provide it with a fifth variable to get the out value:
declare
p_user_id int;
begin
insert_user('user', 'password', 'mail#mail.com', '5', p_user_id);
end;
Note: You don't set the value in your procedure, so you could either let it away at all or you have to set it in your procedure.

Dynamic SQL accept table column as input in a procedure

Hey I am trying to write a procedure in which the user can insert which columns he would like to get as parameter input. As of right now when I run a test script I get this error:
error -1 message error in ct_cu_act_medrecon_pg.spm_search_patientmedrecs =>ORA-00933: SQL command not properly ended
The error is refering to the order by part in the select statement, and when I remove that I get an error saying:
error -1 message error in ct_cu_act_medrecon_pg.spm_search_patientmedrecs =>ORA-00904: "D"."P_INSERTDT_IN": invalid identifier
Here is the spec:
procedure spm_search_patientmedrecs (
p_columnsort_in in varchar2, --which is sort column
p_medmed_in in varchar2, --first column
p_planid_in in varchar2, --second column
p_detmed_in in varchar2, --third column
p_insertdt_in in varchar2, --fourth column
p_ascdesc_in in varchar2, --asc or desc in order by
p_return_cur_out out sys_refcursor,
p_err_code_out out number,
p_err_mesg_out out varchar2
);
Here is the procedure body:
procedure spm_search_patientmedrecs (
p_columnsort_in in varchar2,
p_medmed_in in varchar2,
p_planid_in in varchar2,
p_detmed_in in varchar2,
p_insertdt_in in varchar2,
p_ascdesc_in in varchar2,
p_return_cur_out out sys_refcursor,
p_err_code_out out number,
p_err_mesg_out out varchar2)
is
lv_sql varchar2(32767);
begin
lv_sql := '';
lv_sql := 'select h.p_medmed_in,
h.p_planid_in,
d.p_detmed_in,
d.p_insertdt_in
from membermedicalreconcilationhdr h,
membermedicalreconcilationdet d
where h.membermedreconciliationhdrskey =
d.membermedreconciliationhdrskey
order by h.p_columnsort_in p_ascdesc_in';
p_err_code_out := 0;
OPEN p_return_cur_out FOR lv_sql;
exception
when others then
p_err_code_out := -1;
p_err_mesg_out := 'error in ct_cu_act_medrecon_pg.spm_search_patientmedrecs =>'||sqlerrm;
end spm_search_patientmedrecs;
Here is my test script:
set serveroutput on
declare
type tempcursor is ref cursor;
v_cur_result tempcursor;
errcode number;
errmesg varchar2(1000);
begin
ct_cu_act_medrecon_pg.spm_search_patientmedrecs
('primarymemberplanid',
'membermedreconciliationhdrskey',
'primarymemberplanid',
'membermedreconciliationdetskey',
'inserteddt',
'ASC',
v_cur_result,
errcode,
errmesg
);
-- dbms_output.put_line(v_cur_result);
dbms_output.put_line('error '||errcode||' message '||errmesg);
end;
First off, I know how I'm handeling the error isnt the best way to do it but thats how the person asking me to do this wanted it.
Now I dont know if this is a possible thing to do in Oracle PL/SQL, but if it is I would greatly appreciate some help in pointing me in the right direction. If you guys need any more information feel free to ask and I will assist as best I can (Ive only been working with SQL and PL/SQL for 2 months). Thanks in advance.
Dynamic SQL means assembling strings which are executed as SQL statements. Your string hardcodes the parameter names, whereas what you actually need is the contents of the parameters.
Something like this:
lv_sql := 'select h.'||p_medmed_in||',
h.'||p_planid_in||',
d.'||p_detmed_in||',
d.'||p_insertdt_in||'
from membermedicalreconcilationhdr h,
membermedicalreconcilationdet d
where h.membermedreconciliationhdrskey =
d.membermedreconciliationhdrskey
order by h.'||p_columnsort_in||' '|| p_ascdesc_in;

Resources