function with parameter return two values - sql

hello stack overflow I have encountered an issue i am trying to create a function which needs parameter that will return two values however I'm having an error PLS-00103: Encountered the symbol i dont know where im going wrong if i could get assistance or advice of where im going wrong.
create or replace FUNCTION GET_LOCATIONcname (l_con_id_n in NUMBER)
RETURN NUMBER
IS LOCATION VARCHAR2(30) CST_NAME VARCHAR2(15);
BEGIN
SELECT LOCATION, CST_NAME INTO LOCATION FROM LDS_CONSULTANT WHERE CONSULTANT_ID = l_con_id;
RETURN l_con_id;
END;

Functions in Oracle PL/SQL can only return result value, however, that result value does not need to be an intrinsic/atomic data type, it could be a complex data type such as an array, record, or object data type.
create or replace TYPE My_Object_Type as OBJECT (
location varchar2(30),
cst_name varchar2(15)
;
create or replace FUNCTION GET_LOCATIONcname (l_con_id_n in NUMBER)
RETURN My_Object_Type
IS
My_Result My_Object_Type;
BEGIN
SELECT My_Object_Type(LOCATION, CST_NAME) INTO My_Result
FROM LDS_CONSULTANT
WHERE CONSULTANT_ID = l_con_id;
RETURN My_Result;
END;
Then you can use this function something like this:
declare
My_Result My_Object_Type;
begin
My_Result := GET_LOCATIONcname(1);
dbms_output.put_line(My_Result.location||' '||My_Result.cst_name);
end;

Related

Function Oracle PL SQL bulk collect error PLS-00382: expression is of wrong type

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.

Can we call procedure inside function in oracle PL/SQL? If not then why?

In some places I heard that we cannot call procedure inside function in oracle PL/SQL. May I know why is it so?
Also why cant we call a procedure within a SELECT statement whereas we can call a function in the same SELECT statement.
Yes you can call a procedure from a function in Oracle PL/SQL.
You can't call a procedure from a SELECT statement because it doesn't return a value. A function can be called from a SELECT because it does:
select empno, calc_salary_function(empno) salary
from emp;
Calling a procedure from a SELECT makes no sense really:
select empno, fire_employee(empno) -- Will fail
from emp;
What would you expect to see in the second column of the results?
Procedure is not used to return a value. Procedures performs group of operations to achieve a task, where as function is used to return a value.
Procedure is executed as an operation, function can be used in the select statement derive a value
you can call procedure from function.
create table test(a varchar2(30));
create or replace procedure pro_insert_values
as
begin
insert into test values('anything');
end;
create or replace function fn_get_data
return number
as
begin
pro_insert_values;
return 1;
end;
sql>variable x number
exec :x:=fn_get_data
You can use below code to validate that procedure can be called from inside function.
create table country_name(id number, country varchar2(100));
insert all
into country_name values(1, 'INDIA')
into country_name values(2, 'UK')
SELECT * FROM DUAL;
/
CREATE OR REPLACE FUNCTION COUNTRY_FOUND_NOTFOUND(V_NAME VARCHAR2)
RETURN VARCHAR2
AS
V_COUNTRY VARCHAR2(100);
BEGIN
BEGIN
SELECT COUNTRY INTO V_COUNTRY FROM country_name WHERE COUNTRY = V_NAME;
RETURN 'FOUND';
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT_COUNTRY(V_NAME);
RETURN 'NOT FOUND';
END;
RETURN 'NOT FOUND';
END;
/
CREATE OR REPLACE PROCEDURE INSERT_COUNTRY(V_NAME IN VARCHAR2)
AS
V_ID NUMBER;
BEGIN
SELECT MAX(ID) INTO V_ID FROM COUNTRY_NAME;
INSERT INTO COUNTRY_NAME VALUES(V_ID+1, V_NAME);
END;
/
SET SERVEROUTPUT ON;
DECLARE
V_NAME VARCHAR2(100);
BEGIN
V_NAME := COUNTRY_FOUND_NOTFOUND('SPAIN');
DBMS_OUTPUT.PUT_LINE(V_NAME);
END;

Creating a user defined function in oracle SQL called lastnamefirst

I am using oracle SQL developper.
I am trying to create a function that will accept two parameters (first and last name) and return them as one variable, with the last name showing up first. Here is my function.
CREATE OR REPLACE FUNCTION LASTNAMEFIRST
(
varFirstName IN VARCHAR2,
varLastName IN VARCHAR2
)
RETURN VARCHAR2 AS
BEGIN
DECLARE varFullName VARCHAR2;
DEFINE varFullName := CONCAT(varLastName,' ' ,varFirstName);
RETURN varFullName;
END LASTNAMEFIRST;
I am receiving an error on the semicolon at 'end lastnamefirst' "syntax error"
I keep trying to change small things and that same error just shows up in different places whenever I change things. What am I doing wrong?
Wrong syntax. Should be
SQL> create or replace function lastnamefirst
2 (varfirstname in varchar2,
3 varlastname in varchar2)
4 return varchar2
5 as
6 begin
7 return varlastname||' '||varfirstname;
8 end;
9 /
Function created.
SQL> select lastnamefirst('Little', 'Foot') result from dual;
RESULT
------------------------------
Foot Little
SQL>
What's wrong with your code?
you don't DECLARE within the body; if you do, there's no DECLARE keyword at all, and datatype requires length (such as VARCHAR2(30))
CONCAT accepts only two arguments; use a concatenation operator, double pipe || instead
there's no DEFINE in PL/SQL
I would expect the Oracle syntax to look more like:
CREATE OR REPLACE FUNCTION LASTNAMEFIRST (
in_FirstName IN VARCHAR2,
in_LastName IN VARCHAR2
)
RETURN VARCHAR2 AS
v_FullName varchar2(4000);
BEGIN
v_FullName := in_LastName || ' ' || in_FirstName;
RETURN v_FullName;
END; -- LASTNAMEFIRST;
This can of course be simplified (say by not using a local variable), but it follows the logic of your code.
Using DECLARE where you have is essentially starting a new code block, which is leading to the error you see. In your code, the DECLAREisn't necessary if you move the variable declaration prior to the BEGIN. DEFINE is also invalid. Something like this should work:
CREATE OR REPLACE FUNCTION LASTNAMEFIRST
(
varFirstName IN VARCHAR2,
varLastName IN VARCHAR2
)
RETURN VARCHAR2 AS
varFullName VARCHAR2(100);
BEGIN
varFullName := varLastName || ' ' || varFirstName;
RETURN varFullName;
END LASTNAMEFIRST;
This could be simplified further by removing the variable declaration completely:
CREATE OR REPLACE FUNCTION LASTNAMEFIRST
(
varFirstName IN VARCHAR2,
varLastName IN VARCHAR2
)
RETURN VARCHAR2 AS
BEGIN
RETURN varLastName || ' ' || varFirstName;
END LASTNAMEFIRST;

Pl SQL Oracle PLS-00103: Encountered the symbol "CREATE"

this code takes input for zipcode, city, and state and then inserts that into the table created Address. Prior to inserting data it will check if the zipcode is already in the table, if so calling procedure(error) to display an error code.
Im getting an error code pls-00103: encountered the symbol "CREATE" when trying to execute the code. Here is my code so far. Thanks for any help in advance.
drop table address;
create table address(zipcode NUMBER, city varchar2(30), state varchar2(20));
create or replace procedure error as
begin
dbms_output.put_line('Error Zip Code already found in table');
end error;
declare
zzip number;
ccity varchar2(30);
sstate varchar2(30);
create or replace procedure location(p_zipcode NUMBER,
p_city varchar2,
p_state varchar2) is
zip address.zipcode%type;
cit address.city%type;
st address.state%type;
begin
select count(*) from address into zip where zipcode = zip;
if any_rows_found then
error;
else
Insert into address values(zip, cit, st);
end if;
end location;
begin
select &zipcode into zzip from dual;
select &city into ccity from dual;
select &state into sstate from dual;
procedure location(zzip, ccity, sstate);
end;
/
I'm not sure what you're trying to do, but the following may be closer to what you had in mind:
drop table address;
create table address(zipcode NUMBER, city varchar2(30), state varchar2(20));
declare
zzip number;
ccity varchar2(30);
sstate varchar2(30);
procedure error is
begin
dbms_output.put_line('Error Zip Code already found in table');
end error;
procedure location(p_zipcode NUMBER, p_city varchar2, p_state varchar2) is
zip_count NUMBER;
begin
select count(*)
into zip_count
from address
where zipcode = p_zipcode;
if zip_count > 0 then
error;
else
Insert into address
(zipcode, city, state)
values
(p_zipcode, p_city, p_state);
end if;
end location;
begin
select &zipcode into zzip from dual;
select &city into ccity from dual;
select &state into sstate from dual;
location(zzip, ccity, sstate);
end;
/
Best of luck.
I dont know if I understand your problem correctly, but there are certain correction I'd like to address to answer your problem
First, if you are going to create a procedure/function, do it in a separate worksheet then compile it. Dont compile it together with other anonymous blocks because most of the time, if you dont end your other blocks with '/', errors will surely generate.
Second, your DECLARE statement is misplaced, if you are going to make an anonymous block, make sure DECLARE, BEGIN and END are in line, dont create a procedure/function inside an anonymous block.
Third, you are declaring variables in your procedures and using them but doesnt have an initial value, so it will just pass a null value to the DML statement in your procedure. just use the parameter directly.
Fourth, avoid creating a procedure that only contains dbms_output.put_line. Its silly.
Lastly, your anonymous block that should be calling your procedure, uses '&', please avoid using '&' inside pl/sql as '&' is a feature in SQL*Plus and doesnt have any meaning in PL/SQL, instead, you can use ':' as for binding variables. But you use '&' not in binding variables so you should remove that;
Try this:
drop table address;
/
create table address(zipcode NUMBER, city varchar2(30), state varchar2(20));
/
create or replace procedure location(p_zipcode NUMBER,
p_city varchar2,
p_state varchar2) is
zip address.zipcode%type;
begin
select count(*)
from address
into zip
where zipcode = p_zipcode
and city =p_city
and state = p_state;
if zip > 0 then
dbms_output.put_line('Error Zip Code already found in table');
else
Insert into address values(p_zipcode, p_city, p_state);
end if;
end location;
/
begin
location(:zzip, :ccity, :sstate);
end;

Stored Function in Oracle not Inserting Values into the desired table

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