I have the below code snippet where i am creating a type with 2 attributes.
CREATE OR REPLACE
TYPE test_params IS OBJECT (
F_days number,
F_comments VARCHAR2 (100)
);
/
I am using the above type as below
Declare
tp test_params;
tp1 test_params;
BEGIN
tp:= test_params(1,'asd');
tp.f_days:=1;
dbms_output.put_line(tp.f_days);
END;
It prints 1
Now if I want to add 1 more attribute comments varchar(50) to my type and I dont want to disturb the above code and i want the above output.
Kindly guide me on this
You can create a constructor with optional third argument, then your code will keep working.
create or replace
type test_params is object (
f_days number,
f_comments varchar2 (100),
comments varchar2(50),
constructor function test_params(
f_days number,
f_comments varchar2,
comments varchar2 default null
) return self as result
);
create or replace
type body test_params
as
constructor function test_params(
f_days number,
f_comments varchar2,
comments varchar2 default null
) return self as result
as
begin
self.f_days := f_days;
self.f_comments := f_comments;
self.comments := comments;
return;
end;
end;
I have this function:
CREATE OR REPLACE TYPE products_type AS OBJECT
(
products VARCHAR2 (50),
price VARCHAR2 (50)
);
CREATE OR REPLACE TYPE results_type AS TABLE OF products_type;
create or replace get_sum ( l_products in varchar2(50)
RETURN results_type
IS
l_result results_type;
begin
SELECT distinct products, count(price)
BULK COLLECT INTO l_result
FROM products;
RETURN l_result;
END;
/
DECLARE
l_result varchar2(50) := '0';
BEGIN
l_result := get_sum ('apple')
DBMS_OUTPUT.PUT_LINE('Price total ' || l_result);
END;
I have this table and I want to know what the sum of a product is.
I try to learn how a function works when I want to display more than one column. I found on the internet related to bulk collect and I tried to do so, but I encounter this error:
PLS-00382: expression is of wrong type
What am I doing wrong?
The problem is that in your function GET_SUM, you are returning l_result which is of type results_type. In your anonymous block, you are calling GET_SUM and attempting to assign it to a VARCHAR2(50) variable. The variable you are trying to assign the value to needs to match the return type of the function.
I’m having trouble testing, in SQL Developer 3.2.20.09, an Oracle stored procedure that contains 2 specificities:
a user defined "cursor type" output parameter
a user defined "TABLE OF VARCHAR type" output parameter.
Stored procedure signature:
TYPE ref_cursor_tst IS REF CURSOR;
TYPE arrWarningCode_tst IS TABLE OF VARCHAR2 (4000)
INDEX BY BINARY_INTEGER;
PROCEDURE SP_ITF_CU_DOCUMENT_Test (
p_projectNumber IN VARCHAR2,
p_tag IN VARCHAR2,
p_title IN VARCHAR2,
out_document_curs OUT ref_cursor_tst,
out_errorCode OUT VARCHAR2,
out_arrWarningCode OUT arrWarningCode_tst);
My actual best test code I could end up with:
set serveroutput on size 100000
DECLARE
docRef VARCHAR2(200);
outDocCurs PD360BADMIN.PKG_ITF_GENERAL_TST.ref_cursor_tst;
outErrorCode VARCHAR2(2000);
arrWarningCodes PD360BADMIN.PKG_ITF_GENERAL_TST.arrWarningCode_tst;
i PLS_INTEGER;
doc TBL_OBJECT%ROWTYPE;
BEGIN
dbms_output.put_line('debut de procedure');
docRef:= 'DOC-012';
arrWarningCodes.DELETE;
--call SP
PKG_ITF_GENERAL_TST.SP_ITF_CU_DOCUMENT_TEST (
p_projectNumber => 'XXX',
p_tag => docRef,
p_title => 'Doc title',
out_document_curs => outDocCurs,
out_errorCode => outErrorCode,
out_arrWarningCode => arrWarningCodes);
--print error code
dbms_output.put_line('out_errorCode=' || outErrorCode);
--print output cursor
--dbms_output.put_line(outDocCurs);
LOOP
FETCH outDocCurs INTO doc;
EXIT WHEN outDocCurs%NOTFOUND;
dbms_output.put_line(doc.OBJ_ID||','||doc.OBJ_TAG);
END LOOP;
--print warnings array
IF arrWarningCodes.count > 0 THEN
FOR i IN arrWarningCodes.FIRST .. arrWarningCodes.LAST LOOP
dbms_output.put_line('warning code=' || arrWarningCodes(i) );
END LOOP;
ENd IF;
dbms_output.put_line('fin de procedure');
END;
/
The error I get:
Error report:
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
ORA-06512: at line 30
06504. 00000 - "PL/SQL: Return types of Result Set variables or query do not match"
*Cause: Number and/or types of columns in a query does not match declared
return type of a result set variable, or declared types of two Result
Set variables do not match.
*Action: Change the program statement or declaration. Verify what query the variable
actually refers to during execution.
debut de procedure
out_errorCode=
I've been testing various solutions and syntaxes for days as well as digging the net and requiring help from different sources with no success.
Any clue would be much appreciated.
Assuming TBL_OBJECT is a table of some object type which has the two fields obj_id and obj_tag; and the procedure is currently doing something like:
open out_document_curs for select * from tbl_object;
... then there are two ways to make this work. The first is to change the variables you're fetching into to match the object fields, rather than the object itself:
DECLARE
...
-- doc TBL_OBJECT%ROWTYPE;
doc_obj_id TBL_OBJECT.OBJ_ID%TYPE;
doc_obj_tag TBL_OBJECT.OBJ_TAG%TYPE;
BEGIN
...
and then change the fetch and display:
LOOP
FETCH outDocCurs INTO doc_obj_id, doc_obj_tag;
EXIT WHEN outDocCurs%NOTFOUND;
dbms_output.put_line(doc_obj_id||','||doc_obj_tag);
END LOOP;
If the object has more fields then you'd need to define them all and specify them in the fetch too.
The other is to modify the procedure so that it returns an object type:
open out_document_curs for select value(t) from tbl_object t;
Then your calling anonymous block will work as it is, as the simple query will return the object itself rather than the fields within it.
Which you do will depend on how the procedure will really be used, rather than your test call.
With some dummy set-up:
create type doc_obj as object (obj_id number, obj_tag varchar2(10));
/
create table tbl_object of doc_obj;
insert into tbl_object values (doc_obj(1, 'Test'));
And a dummy package body with the procedure simplified as:
PROCEDURE SP_ITF_CU_DOCUMENT_Test (
p_projectNumber IN VARCHAR2,
p_tag IN VARCHAR2,
p_title IN VARCHAR2,
out_document_curs OUT ref_cursor_tst,
out_errorCode OUT VARCHAR2,
out_arrWarningCode OUT arrWarningCode_tst)
IS
BEGIN
open out_document_curs for select value(o) from tbl_object o;
out_errorCode := 'OK';
out_arrWarningCode(1) := 'Danger!';
END SP_ITF_CU_DOCUMENT_Test;
Then calling your code exactly as you have it in the question (minus the schema name) gives:
anonymous block completed
debut de procedure
out_errorCode=OK
1,Test
warning code=Danger!
fin de procedure
Using the other approach, with the individual variables for the object fields, gives the same result too.
Hi Please i need assistance as im stuggling with the following error:
PLS-00201: identifier 'NO_EMPLOYEES' must be declared
CREATE or replace PACKAGE police_employee_mgmt AS
no_employees NUMBER;
FUNCTION insert_employee
(emp_id NUMBER, emp_name VARCHAR2, emp_grade NUMBER, emp_password VARCHAR2, emp_username VARCHAR2)
RETURN NUMBER;
PROCEDURE delete_employee(emp_id NUMBER);
PROCEDURE change_employee_grade(emp_id NUMBER, emp_grade NUMBER);
END police_employee_mgmt;
then a function is created to give the variable a value:
CREATE OR REPLACE FUNCTION number_of_employees
RETURN NUMBER IS
total_employees NUMBER;
BEGIN
SELECT COUNT(*)
INTO total_employees
FROM pl_police_employee;
RETURN(total_employees);
END;
Then...
BEGIN
no_employees := number_of_employees();
END;
As the error states, you need to declare no_employees. I asume your last code block is outside the package where you did declare it. I think you can use anonymous declares as well:
DECLARE
num_employees NUMBER;
BEGIN
num_employees := number_of_employees();
...
END
Here is my Code given below. I am trying to add 5 parameters which the function takes into the table Employee. But I am not successful in doing it and have tried a lot of things.
Error
ORA-01858: a non-numeric character was found where a numeric was
expected ORA-06512: at "xxxxxxx.A1SF_ADDEMP", line 14
01858. 00000 - "a non-numeric character was found where a numeric was expected"
*Cause: The input data to be converted using a date format model was
incorrect. The input data did not contain a number where a number was
required by the format model.
*Action: Fix the input data or the date format model to make sure the
elements match in number and type. Then retry the operation.
Plus how do I test a Stored function that has a Insert/Update or Delete Statement in it?
Execution Statement
Select A1SF_ADDEMP('Adesh', '33', 'M', 8000, '26/03/1990')
From dual;
Code
CREATE OR REPLACE Function A1SF_ADDEMP
(pEmpName In Varchar2,
pTaxFileNo In Varchar2,
pGender In Varchar2,
pSalary In Number,
pBirthdate In Varchar2
) Return Varchar2
Is
tEmpId Number(38,0);
tBirthDate Date;
BEGIN
tEmpId := A1Seq_Emp.nextval;
tBirthdate := to_date('pBirthdate','dd/mm/yyyy');
Insert Into Employee(EmpId, EmpName, TaxFileNo, Gender, Salary, Birthdate)
Values (tEmpId, pEmpName, pTaxFileNo, pGender, pSalary, tBirthdate);
Commit;
Return null;
END;
Firstly you cannot call a function with DML in it in a select statement. You have to assign the output to a variable in a PL/SQL block, something like:
declare
l_output number;
begin
l_output := my_function(variable1, variable2);
end;
It's bad practice to do DML in a function; partly because it causes the errors you're coming across. You should use a procedure as detailed below. The other reason for this is that you're as always returning null there's no need to return anything at all!
create or replace procedure my_procedure ( <variables> ) is
begin
insert into employees( <columns> )
values ( <values > );
end;
The specific reason for your error is this line:
tBirthdate := to_date('pBirthdate','dd/mm/yyyy');
pBirthdate is already a string; by putting a ' around it you're passing the string 'pBirthdate' to the function to_date and Oracle can't convert this string into a day, month or year so it's failing.
You should write this as:
tBirthdate := to_date(pBirthdate,'dd/mm/yyyy');
You also don't need to specify number(38,0), you can just write number instead.
It is possible to return a value from a procedure using the out keyword. If we assume that you want to return empid you could write is as something like this:
create or replace procedure A1SF_ADDEMP (
pEmpName in varchar2
, pTaxFileNo in varchar2
, pGender in varchar2
, pSalary in number
, pBirthdate in varchar2
, pEmpid out number
) return varchar2 is
begin
pempid := A1Seq_Emp.nextval;
Insert Into Employee(EmpId, EmpName, TaxFileNo, Gender, Salary, Birthdate)
Values ( pEmpId, pEmpName, pTaxFileNo, pGender
, pSalary, to_date(pBirthdate,'dd/mm/yyyy');
end;
To just execute the procedure call it like this:
begin
A1SF_ADDEMP( EmpName, TaxFileNo, Gender
, Salary, Birthdate);
commit;
end;
If you want to return the empid then you can call it like this:
declare
l_empid number;
begin
l_empid := A1SF_ADDEMP( EmpName, TaxFileNo, Gender
, Salary, Birthdate);
commit;
end;
Notice how I've moved the commit to the highest level, this is to avoid committing stuff in every procedure when you might have more things you need to do.
Incidentally, if you're using Oracle 11g then there's no need to assign the value A1Seq_Emp.nextval to a variable. You can just insert it directly into the table in the values list. You, of course won't be able to return it, but you could return A1Seq_Emp.curval, as long as there's nothing else getting values from the sequence.
You should use a procedure (instead of a function) if you are not returning any values.
If you look at the line mentioned in the error message you can spot your error:
tBirthdate := to_date('pBirthdate','dd/mm/yyyy');
You are passing the string literal 'pBirthdate' to the to_date() call. But you want to pass the parameter, so it should be
tBirthdate := to_date(pBirthdate,'dd/mm/yyyy');
(note the missing single quotes arount pBirthdate).
So as a procedure the whole thing would look like this:
CREATE OR REPLACE PROCEDURE A1SF_ADDEMP
(pEmpName In Varchar2,
pTaxFileNo In Varchar2,
pGender In Varchar2,
pSalary In Number,
pBirthdate In Varchar2
)
IS
BEGIN
Insert Into Employee(EmpId, EmpName, TaxFileNo, Gender, Salary, Birthdate)
Values (A1Seq_Emp.nextval, pEmpName, pTaxFileNo, pGender, pSalary, to_date(pBirthdate,'dd/mm/yyyy'));
Commit;
END;
To run it:
execute A1SF_ADDEMP('Adesh', '33', 'M', 8000, '26/03/1990');
In your situation you need to use procedure with out parameter where your out param is your returning param that contains your desirable value. This is I think best practice in this situation when you want to use DML in select statement.
Second way to do it but its not a good practice is to use one function like yours but before return a value you need to use if statement to check what is the value and if value is what you desire to call in this if statement PRAGMA AUTONOMOUS_TRANSACTION procedure which will do your DML independently of function calling to it. For more information about pragma transactions your can read here:
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/autonotransaction_pragma.htm
Best Regards and hope I was helpful