How to view/verify a procedure result? - sql

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.

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.

Execute immediate select returns no values

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;

PL/SQL Procedure with SELECT return value

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

Displaying data through stored procedure

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

Basic Oracle question

I am new to oracle. When I create a stored procedure using:
CREATE OR REPLACE PROCEDURE PROCEDURE1
AS
BEGIN
SELECT FIRSTNAME,
LASTNAME
INTO FirstName,LastName
FROM EMPLOYEE;
END PROCEDURE1;
i get the following errors:
PL/SQL Statement Ignored
Identifier FIRSTNAME must be declared
ORA-00904 Invalid identifier
You need to declare variables before you attempt to populate them:
CREATE OR REPLACE PROCEDURE PROCEDURE1
AS
FirstName EMPLOYEE.FIRSTNAME%TYPE;
LastName EMPLOYEE.LASTNAME%TYPE;
BEGIN
SELECT FIRSTNAME,
LASTNAME
INTO FirstName,LastName
FROM EMPLOYEE;
END PROCEDURE1;
The %TYPE notation is shorthand for data type declaration that matches the column data type. If that data type ever changes, you don't need to update the procedure.
You need to declare the variables.
CREATE OR REPLACE
PROCEDURE PROCEDURE1 AS
V_FIRSTNAME VARCHAR2(60);
V_LASTNAME VARCHAR2(60);
BEGIN
SELECT FIRSTNAME,LASTNAME
INTO V_FIRSTNAME ,V_LASTNAME
FROM EMPLOYEE;
END PROCEDURE1;
In reply to your comment, SQL statements in PL/SQL block can fetch only 1 record. If you need to fetch multiple records, you will need to store the records in a cursor and process them.
CREATE OR REPLACE
PROCEDURE PROCEDURE1 AS
CURSOR EMP_CUR IS
SELECT FIRSTNAME,LASTNAME
FROM EMPLOYEE;
EMP_CUR_REC EMP_CUR%ROWTYPE;
BEGIN
FOR EMP_CUR_REC IN EMP_CUR LOOP
-- do your processing
DBMS_OUTPUT.PUT_LINE('Employee first name is ' || EMP_CUR_REC.FIRSTNAME);
DBMS_OUTPUT.PUT_LINE('Employee last name is ' || EMP_CUR_REC.LASTNAME);
END LOOP;
END PROCEDURE1;
To explain:
EMP_CUR holds the SQL statement to be executed.
EMP_CUR_REC holds the records that will be fetched by the SQL statement.
%ROWTYPE indicates that the Record will be of the same data type as the row which holds the data
The FOR LOOP will fetch each record, and you can do whatever processing that needs to be done.
I think the "AS" keyword won't work. If it doesn't work, then use "IS".
Rest are fine and very good tips.
If you need any help regarding PL/SQL, then you can have a look at this link. It is very simple and easy to understand;
http://plsql-tutorial.com/
This is my solution to the error which you are getting;
CREATE OR REPLACE PROCEDURE PROCEDURE1 IS
v_FIRSTNAME EMPLOYEE.FIRSTNAME%TYPE;
v_LASTNAME EMPLOYEE.LASTNAME%TYPE;
CURSOR EMPCURSOR IS
SELECT FIRSTNAME, LASTNAME FROM EMPLOYEE;
BEGIN
IF NOT EMPCURSOR%ISOPEN THEN
OPEN EMPCURSOR;
END IF;
LOOP
FETCH EMPCURSOR INTO V_FIRSTNAME,V_LASTNAME;
EXIT WHEN EMPCURSOR%NOTFOUND;
END LOOP;
IF EMPCURSOR%ISOPEN THEN
CLOSE EMPCURSOR;
END;
END PROCEDURE1;
You can also use DBMS_OUTPUT.PUT_LINE(V_FIRSTNAME || ','|| V_LASTNAME), inside the loop to display the output. but in order to do that, you first need to execute the command server output on
In a response to #Sathya's answer above #kayak asked "Can i have something like Select * from Tablename or select firstname,lastname from tablename , like we have in sql server".
Yes, you can do that, but you'll either need to include a WHERE clause or use a cursor. If you include a WHERE clause which limits your results to a single row you could write something like
CREATE OR REPLACE PROCEDURE PROCEDURE1
IS
rowEmployees EMPLOYEE%ROWTYPE;
BEGIN
SELECT *
INTO rowEmployees
FROM EMPLOYEE
WHERE EMPLOYEE_ID = 12345;
END PROCEDURE1;
On the other hand, if you either don't have a WHERE clause because you wish to process all rows in the table, or you have a WHERE clause which doesn't limit your results to a single row you could use a cursor in the following manner:
CREATE OR REPLACE PROCEDURE PROCEDURE1 IS
BEGIN
FOR rowEmployees IN (SELECT *
FROM EMPLOYEE
WHERE EMPLOYEE_ID IN (12345, 67890, 111213, 141516))
LOOP
<do something with rowEmployees here>
END LOOP;
END PROCEDURE1;
Share and enjoy.