PL/SQL Procedure with SELECT return value - sql

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);

Related

Issue with PL/SQL Output

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.

PL/SQL query with parameter

I am familiar with MSSQL and using a parameter within the query, but I am not sure how I would do this within PL/SQL.
DECLARE
LSITEID NUMBER := 100001;
BEGIN
SELECT * from invoicehead ih
JOIN sitemaster sm on sm.SITEIID = ih.SITEIID
JOIN invoiceline il on il.invoiceIID = ih.invoiceIID
WHERE
ih.StartDate BETWEEN '2015-12-01' AND '2016-03-07'
AND SITEIID IN ( LSITEID)
END;
Right now I am testing this within Pl/SQL. But essentially I would be passing in the query with the parameter from MSSQL Linked Server OPENQuery.
How I can run the above query in PL/SQL with the parameter?
There is plenty of other resource for finding an answer, e.g. here (Tutorialspoint) or specifically here (plsql-tutorial). But perhaps I have missed your point.
To not remain on merely citing links, your query could look like this:
DECLARE
LSITEID integer;
BEGIN
LSITEID := 100001;
-- dostuff
END;
Two things to note: First, in a declare part (as I have learnt it) you should avoid assigning values. Second, if you intend to pass in different parameters you could/should use a procedure.
In PL/SQL you just use the name of the argument. In the following example, the argument is P_VALUE, note select statement says where dummy = p_value.
DECLARE
FUNCTION dummycount (p_value IN DUAL.dummy%TYPE)
RETURN INTEGER
AS
l_ret INTEGER;
BEGIN
SELECT COUNT (*) c
INTO l_ret
FROM DUAL
WHERE dummy = p_value;
RETURN l_ret;
END dummycount;
BEGIN
DBMS_OUTPUT.put_line ('A: ' || dummycount (p_value => 'A'));
DBMS_OUTPUT.put_line ('X: ' || dummycount (p_value => 'X'));
END;
This results in the following output:
A: 0
X: 1

PLSQL SELECT INTO FROM parameter

I created a function that should return the max id from a table(parameter)
CREATE OR REPLACE FUNCTION getmaxid
(
P_TABLE IN VARCHAR2
)
RETURN NUMBER IS
v_maxId NUMBER(38);
BEGIN
SELECT MAX(id) INTO v_maxId FROM P_TABLE;
RETURN v_maxId;
END getmaxid
However, i keep getting the error message "ORA-00942: table or view does not exist" on this line:
SELECT MAX(id) INTO v_maxId FROM P_TABLE;
Like explained earlier, you need to use dynamic SQL to perform the operation. In this case, p_table is a variable. The solution to this is to build a string that will contain the SQL and dynamically execute it one you've build the query.
The example below uses, DUAL, but the table name is arbitrary.
Here is what you're looking for, take the function outside of the block, I left it like this so that you can test it..
DECLARE
FUNCTION getmaxid (p_table IN VARCHAR2)
RETURN NUMBER
IS
v_maxid NUMBER (38);
v_select VARCHAR2 (200);
cnt SYS_REFCURSOR;
BEGIN
v_select := 'SELECT COUNT(*) FROM ' || p_table;
DBMS_OUTPUT.put_line (v_select);
EXECUTE IMMEDIATE v_select INTO v_maxid;
RETURN v_maxid;
END getmaxid;
BEGIN
DBMS_OUTPUT.put_line (getmaxid ('DUAL'));
END;

SQL - Oracle Functions using variables for schema names

I am writing some oracle stored procedures where we have conditional logic which effects which schema we are working from and I am not sure how to do this in the sql for the stored proc. If I am working with prepared statements then its fine but in the scenario where I am just executing a query to say populate another variable then I dont know how to do this. For example
PROCEDURE register (
incustomer_ref in VARCHAR2,
incustomer_type in VARCHAR2,
outreturn_code out VARCHAR2
)
IS
customer_schema varchar2(30);
record_exists number(1);
BEGIN
if incustomer_type='a' then
customer_schema:='schemaA';
elsif incustomer_type='b' then
customer_schema:='schemaB';
end if;
--This type of command I cant get to work
select count(*) into record_exists from **customer_schema**.customer_registration where customer_ref=incustomer_ref
--but a statement like this i know how to do
if record_exists = 0 then
execute immediate 'insert into '||customer_schema||'.customer_registration
values ('||incustomer_ref||','Y',sysdate)';
end if;
Can anyone shine some light on what I am missing here.
Cheers
you can use execute immediate also for select statment:
execute immediate 'select count(*) from '|| customer_schema
|| '.customer_registration where customer_ref= :b1'
into record_exists using incustomer_ref;

How to view/verify a procedure result?

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.