I created this procedure in Oracle SQL Developer.
CREATE OR REPLACE PROCEDURE CUST_NAME_LIMIT(
I_CUSTOMER_NUM IN CUSTOMER.CUSTOMER_NUM%TYPE,
I_CUSTOMER_NAME OUT CUSTOMER.CUSTOMER_NAME%TYPE,
I_CREDIT_LIMIT OUT CUSTOMER.CREDIT_LIMIT%TYPE)
AS
BEGIN
SELECT CUSTOMER_NAME, CREDIT_LIMIT
INTO
I_CUSTOMER_NAME, I_CREDIT_LIMIT
FROM
CUSTOMER
WHERE
CUSTOMER_NAME = I_CUSTOMER_NAME;
DBMS_OUTPUT.PUT_LINE(I_CUSTOMER_NAME);
DBMS_OUTPUT.PUT_LINE(I_CREDIT_LIMIT);
END;
When I try to display the output with this below I get an error
BEGIN
CUST_NAME_LIMIT('126');
END;
It should out put
TOYS GALORE
7500
Only if you told us which error you got, instead of letting us guess. But hey, it is more fun this way!
As you declared a procedure to accept one IN and two OUT parameters:
create or replace procedure cust_name_limit(
i_customer_num in customer.customer_num%type,
i_customer_name out customer.customer_name%type,
i_credit_limit out customer.credit_limit%type)
as
begin
select customer_name, credit_limit
into i_customer_name, i_credit_limit
from customer
where customer_name = i_customer_name;
end;
you have to do the same when calling it:
declare
l_custname customer.customer_name%type;
l_credlim customer.credit_limit%type;
begin
CUST_NAME_LIMIT('126', l_custname, l_credlim);
dbms_output.put_line(l_custname ||' - '|| l_credlim);
end;
/
Displaying the result from within the procedure doesn't make much sense; do so once it returns values.
Related
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;
I have select statement
select name, surname
from student
where id_student = 1;
It returns
name surname
Bob Smith
I want to create procedure with same select statement, using execute immediate:
create or replace procedure select_procedure
as
begin
execute immediate
'select name, surname
from student
where id_student = 1';
end;
/
exec select_procedure;
When this procedure is executed it shows PL/SQL procedure successfully completed. How do I get the result? (set serveroutput is on)
You have to select into something. If you don't then the query isn't even executed (though it is parsed).
create or replace procedure select_procedure
as
l_name student.name%TYPE;
l_surname student.name%TYPE;
begin
execute immediate
'select name, surname
from student
where id_student = 1'
into l_name, l_surname;
end;
/
But, in no particular order: (a) you should use bind variables instead of having the literal value 1 embedded in the dynamic statement; (b) this doesn't need to be dynamic at all; and (c) the caller won't be able to see the values returned by the query anyway - unless you select into OUT arguments instead, or display them with dbms_output() (although that should really only be used for debugging as you can't control whether the client will show it).
So you could do:
create or replace procedure select_procedure
as
l_name student.name%TYPE;
l_surname student.name%TYPE;
begin
select name, surname
into l_name, l_surname
from student
where id_student = 1;
dbms_output.put_line('name=' || l_name ||', surname=' || l_surname);
end;
/
or
create or replace procedure select_procedure (
p_name OUT student.name%TYPE,
p_surname OUT student.name%TYPE
)
as
begin
select name, surname
into p_name, p_surname
from student
where id_student = 1;
end;
/
and have your caller pass in its own variable names to populate, and then do whatever it needs with those. The caller would usually also pass in the ID you're looking for, so you don't have the 1 hard-coded.
It doesn't seem like a procedure is really the best mechanism for this though.
Also, using a select ... into (static or dynamic) will error if the query returns zero rows or more than one row. It will only work if there is exactly one row returned. A cursor would handle any number of rows - but unless you are just printing the results (as #Jayanth shows) you need to pass the cursor back to the caller instead. You could do a bulk collect into a collection instead, but you still have to do something with that.
You have to write a cursor for this.Please find below the syntax for the same.
Syntax:
create or replace procedure select_procedure
as
CURSOR <cursor_name> IS <SELECT statement without semicolon>;
BEGIN
FOR record IN <cursor_name>
LOOP
Dbms_output.put_line(‘Record Fetched:‘||record.name);
Dbms_output.put_line(‘Record Fetched:‘||record.surname);
END LOOP;
END;
New to PL/SQL and I've tried to mess around with this and figure it out, but at a loss. Hoping for you guy's expertise and guidance.
Here's the code I have, hopefully you can kind of see where I am trying to get to. I know I need a cursor or a loop, maybe to get this to work properly. However, I am not sure where placement goes and how to get this to work.
Any help is appreciated.
create or replace
procedure customer_credit(cust_ID IN NUMBER) AS
credit_num NUMBER;
begin
select CUSTOMER_ID, CREDIT_LIMIT from OE.CUSTOMERS WHERE CUSTOMER_ID=cust_ID;
dbms_output.put_line('Credit Limit = ', || credit_num);
end;
/
exec customer_credit(145);
There are a variety of options. One is to use a SELECT... INTO:
create or replace
procedure customer_credit(cust_ID IN NUMBER) AS
credit_num NUMBER;
begin
select CREDIT_LIMIT
into credit_num
from OE.CUSTOMERS WHERE CUSTOMER_ID=cust_ID;
dbms_output.put_line('Credit Limit = ', || credit_num);
end;
It the row is not found, this will generate an exception. You can fix that either by adding an exception handler, or use an explicit open/fetch/close cursor method. If you are executing the procedure from sqlplus, you need to first call
set serveroutput on
to see the results of dbms_output.
If you want the value to be returned, it is better to define this as a FUNCTION and then invoke the function in your code. This will allow you to use it in both PL/SQL procedures and SELECT statements. You should also use exception handlers to handle situations. I have modified your example to illustrate the changes needed:
create or replace
function customer_credit(cust_ID IN NUMBER)
return number
IS
credit_num NUMBER;
begin
select CREDIT_LIMIT
into credit_num
from OE.CUSTOMERS WHERE CUSTOMER_ID=cust_ID;
dbms_output.put_line('Credit Limit = ', || credit_num);
return(credit_num);
exception
when NO_DATA_FOUND then
return(0);
end;
/
select customer_credit(145) from dual;
Hope that helps.
You may use a Cursor, alternatively :
create or replace procedure customer_credit( cust_ID IN NUMBER) as
begin
for c in ( select CUSTOMER_ID, CREDIT_LIMIT from CUSTOMERS WHERE CUSTOMER_ID=cust_ID )
loop
dbms_output.put_line('Credit Limit = '|| c.CREDIT_LIMIT);
end loop;
end;
By the way, there's a typo (comma) which should be removed inside dbms_output.put_line() clause. As #OldProgrammer stated, set serveroutput on should be issued to see the results .
I believe Your Procedure is compiled with warnings, you've declared the variable credit_num, but are not passing any value into this variable.(So How Can This Variable will return Something if it doesn't have anything.)
If you want to get the CREDIT_LIMIT from Your Table Then You should Write Your code using Select Into for ex:-
select CREDIT_LIMIT
into credit_num
from OE.CUSTOMERS
where CUSTOMER_ID=cust_id;
Just change your select statement and you're good to go with your Program.
this will work :
create or replace
procedure customer_credit(cust_ID IN NUMBER) AS
credit_num NUMBER;
begin
select CREDIT_LIMIT into credit_num from OE.CUSTOMERS WHERE CUSTOMER_ID=cust_ID;
dbms_output.put_line('Credit Limit = ', || credit_num);
end;
/
exec customer_credit(145);
Create or replace procedure disp(pEMPLASTNAME varchar2)
IS
Row employee%rowtype;
begin
select * into row from employee where EMPLASTNAME=’pEMPLASTNAME’ ;
dbms_output.put_line('Name: '||Row.EMPID||' '|| Row.EMPNAME);
End;
/
BEGIN
disp(‘Mark’);
END;
/
Hello, I am trying to display data from a a table using stored procedures. The last name is passed as a parameter through the stored procedure and upon execution , the stored procedure should display all the rows which have the last name . Here is the error that i get; pls help! :-
SQL> BEGIN
disp('Mark');
END;
/
BEGIN
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "TEST.DISP", line 5
ORA-06512: at line 2
No need of the quotes:
select * into row from employee where EMPLASTNAME=pEMPLASTNAME;
However, you may not have any data for that variable's value anyway (i.e. one day, it may happen)
That's why I recommend you catch the exception and treat it (see EXCEPTION block)
pd: it is a good practice to not use reserved words such as row. I recommend you name your variable another way.
I would suggest using a cursor to select all rows and then looping through the cursor to print the result:
Create or replace procedure disp(pEMPLASTNAME varchar2)
IS
Cursor row_select is
select EMPID, EMPNAME from employee where emplastname = pEMPLASTNAME;
-- and whatever columns you need to print, using * isn't good practice
begin
for item in row_select loop
dbms_output.put_line('Name: '||item.EMPID||' '|| item.EMPNAME);
end loop;
End;
/
BEGIN
disp(‘Mark’);
END;
/
Can someone explain how to see the results of a procedure, everything is working fine and the code is valid, executed and compiled with no errors. Now how can I see the results as Query or anything.
The ex procedure is about sum of salary.
CREATE OR REPLACE PROCEDURE HR.TOTAL_SALARY AS
total_salary NUMBER(12,2);
BEGIN
SET TRANSACTION READ ONLY;
SELECT SUM (salary)
INTO total_salary
FROM employees;
DBMS_OUTPUT.PUT_LINE('Total salary 1: ' || total_salary);
COMMIT;
END;
Are you running this in SQL*Plus? Have you "set serveroutput on;"?
I recommend for this a function
CREATE OR REPLACE FUNCTION HR.TOTAL_SALARY return number AS
total_salary NUMBER(12,2);
BEGIN
SELECT SUM (salary)
INTO total_salary
FROM employees;
return total_salary;
END;
The usage for this is like:
select hr.TOTAL_SALARY() as total_sal from dual.
To output the results of a select statement in a procedure you need to use a cursor.
create procedure myproc
(in_variable IN number, out_records OUT sys_refcursor)
as
begin
open out_records for
select * from mytable
where column = in_variable;
end;
then to use it, declare the cursor, execute the proc, and output the results.
variable records refcursor;
exec myproc(1, :records);
print :records;
(no promises that the above is syntactically perfect - I'm away from the DB right now. But it should be close enough to get you in the right direction.)
Oh - and you can use a user-defined cursor type inside of a package, if that is appropriate for your environment.