Basic Oracle question - sql

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.

Related

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;

how to get multiple records by passing parameter to where clause in oracle pl/sql

table :
create table emp
(
E_ID number,
E_NAME varchar2(30)
);
select * from emp;
101 name1
102 name2
My code:
declare
v1 varchar2(30) := '101,102';
begin
for i in (select e_id,e_name
from emp
where e_id in (v1)) loop
dbms_output.put_line(i.e_id);
end loop;
end;
/
ISSUE:
Getting ORA -01722:invalid number
Please help to understand this issue and suggest me the solution.
It is syntax error.
E_ID is of number type and you are comparing it will v1 which is varchar2 type.
Welcome to SO. A great place to ask questions: I can see what you're trying to do. Syntactically, you'd be forgiven for trying to query your table using the "IN" clause, but as others have said, this can not be done where you have committed your numeric values into a varchar2. In anycase, an array or a collection, (even if you had created one) it isn't an easy option here. But you do have a variety of solutions open to you:
1/ Place your numbers into an Array and use a condition in your loop and check that e_id forms part of the your array. But in-elegant!
2/ Create a global temporary table and add your numbers in and add the table into your query, specify a join.
3/ Create some dynamic PL/SQL using a Ref Cursor. I've included an example for you below, using your table (emp) and values. In this case, you'd be able to build up your string according to the values you want to query. See below. The varchar2 string: sqlString can be manipulated however you want. Paste into a test-harness and see. Hope it helps
declare
type refCursor is ref cursor;
tableCursor refCursor;
emp_record emp%rowtype;
sqlString varchar2(200);
begin
-- Dynamic SQL statement with placeholder:
sqlString := 'SELECT * FROM emp WHERE e_id in
(101, 102)';
-- Open cursor:
open tableCursor for sqlString;
-- Fetch rows from result set one at a time:
loop
fetch tableCursor
into emp;
exit when tableCursor%notfound;
dbms_output.put_line(emp.e_id);
end loop;
-- Close cursor:
close tableCursor;
end;

PLSQL Call Procedure If Exists Clause

I'm using Oracle 9i.
Cue pseudo-code!
I have Stored Procedure A:
PROCEDURE stored_proc_a
IS
BEGIN
insert into...
END;
Then, I have Stored Procedure B:
PROCEDURE stored_proc_b
IS
BEGIN
stored_proc_a
WHERE NOT EXISTS (SELECT * FROM...);
END;
As you can see from my pseudo-code, I would like to call procedure A from procedure B, if a given row does not exist in a table.
I can't find any documentation that would suggest that the WHERE EXISTS clause can be used with a procedure call (the examples show its use with INSERT, UPDATE and DELETE).
Can I use WHERE EXISTS with a procedure call, and if not, what would be the correct code to do a procedure call based on the absence of a particular record in a table?
The correct way of doing this is the following:
PROCEDURE stored_proc_b
IS
num_rows number;
BEGIN
select COUNT(*) into num_rows
FROM my_table
WHERE my_table.xyz = 123; -- (whatever is appropriate)
if num_rows < 1
then
stored_proc_a;
end if;
END;
Figured this out thanks to Nicholas Krasnov and WBAR for their info on other posts.
Another way of achieving the same, in case you you want to call it for multiple rows and want to use data from Table in procedure B-
PROCEDURE stored_proc_b
IS
BEGIN
FOR rec IN (SELECT COL1 FROM <<TABLE1>> T1 WHERE NOT EXISTS (SELECT * FROM <<TABLE2>> T2...WHERE T1.JOIN_COL = T2.JOIN_COL))
LOOP
stored_proc_a;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
rollback;
END;

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

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.