Getting PLS-00905 and PLS-00304 errors, not sure why? - sql

I've got the below functions but for some reason I'm getting the above mentioned errors. I've gone through it twice and I'm not sure what the problem is. Can anyone help?
Code is:
CREATE OR REPLACE PACKAGE DATA_CLEANUP AS
FUNCTION AVERAGE_GRADE (IN_StudentID IN NUMBER) RETURN NUMBER;
END DATA_CLEANUP;
/
CREATE OR REPLACE PACKAGE BODY DATA_CLEANUP AS
FUNCTION AVERAGE_GRADE (IN_StudentID IN NUMBER) RETURN NUMBER AS
AvgGrade NUMBER;
BEGIN
SELECT AVG(PercentGrade) INTO AvgGrade FROM GRADE
WHERE StudentID = IN_StudentID;
RETURN AvgGrade;
END AVERAGE_GRADE;
END;
/

PLS-00905: object is invalid
PLS-00304: cannot compile body of without its specification
If table exists (I created a dummy one):
SQL> create table grade as select 15 percentgrade, 1 studentid from dual;
Table created.
Create package specification first ...
SQL> CREATE OR REPLACE PACKAGE DATA_CLEANUP AS
2 FUNCTION AVERAGE_GRADE (IN_StudentID IN NUMBER) RETURN NUMBER;
3 END DATA_CLEANUP;
4 /
Package created.
... and package body next:
SQL> CREATE OR REPLACE PACKAGE BODY DATA_CLEANUP AS
2 FUNCTION AVERAGE_GRADE (IN_StudentID IN NUMBER) RETURN NUMBER AS
3 AvgGrade NUMBER;
4 BEGIN
5 SELECT AVG(PercentGrade) INTO AvgGrade FROM GRADE
6 WHERE StudentID = IN_StudentID;
7 RETURN AvgGrade;
8 END AVERAGE_GRADE;
9 END;
10 /
Package body created.
SQL>
Everything compiles. Does it work?
SQL> select data_cleanup.average_grade(1) result from dual;
RESULT
----------
15
SQL>
It works (disregard stupid sample data, but - there are no errors).
If you got errors, you did something wrong. Can't tell what; do you have table grade in your schema?

Related

Select a column from table return by function in Oracle

I have a function that returns a table of custom objects. I wish to select a certain column by name from the returned result.
create or replace type sd_Serial_Number as object (
serial_number VARCHAR2(32)
);
The table of objects
create or replace type sd_Serial_Number_Table as table of sd_Serial_Number;
The function
create function get_result
return sd_Serial_Number_Table as
v_ret sd_Serial_Number_Table;
begin
select sd_Serial_Number(selected.SERIAL_NUMBER)
bulk collect into v_ret
from (
selection here
) selected;
return v_ret;
end get_result;
When I call the function this way, I get a result with a single column called SERIAL_NUMBER
select * from table(get_result());
However, I can't do something like this
select SERIAL_NUMBER from table(get_result());
Is there a way to select the column SERIAL_NUMBER ?
"I can't" is difficult to debug. I'll show you that I can (on the same database version you use).
SQL> SELECT * FROM v$version WHERE rownum = 1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
SQL> CREATE OR REPLACE TYPE sd_serial_number AS OBJECT
2 (
3 serial_number VARCHAR2 (32)
4 );
5 /
Type created.
SQL> CREATE OR REPLACE TYPE sd_serial_number_table AS TABLE OF sd_serial_number;
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION get_result
2 RETURN sd_serial_number_table
3 AS
4 v_ret sd_serial_number_table;
5 BEGIN
6 SELECT sd_serial_number (deptno)
7 BULK COLLECT INTO v_ret
8 FROM dept;
9
10 RETURN v_ret;
11 END get_result;
12 /
Function created.
Testing:
SQL> SELECT * FROM TABLE (get_result ());
SERIAL_NUMBER
--------------------------------
10
20
30
40
SQL> SELECT serial_number FROM TABLE (get_result ());
SERIAL_NUMBER
--------------------------------
10
20
30
40
SQL>

Stored procedure variable error in PLSQL when declaring variables

Using Oracle 11g when creating the following stored procedure
create or replace PROCEDURE sp_EqualVote(AREA IN NVARCHAR2, DATEOFVOTE IN DATE)
IS
DECLARE test nvarchar(255);
BEGIN
SELECT
AREA,
DATEOFVOTE,
CASE
WHEN (REMAINVOTES = LEAVEVOTES) THEN REMAINVOTES
END AS EqualVote
INTO test
FROM VOTING
WHERE REMAINVOTES = LEAVEVOTES;
END;
END;
I encounter the following error, I'm not quite sure where to go
PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following: begin function pragma procedure subtype type <an identifier> <a double-quoted delimited-identifier> current cursor delete exists prior external language The symbol "begin" was substituted for "DECLARE" to continue.
I'm a university student and not really that familiar with PLSQL. The idea is the stored procedure should display if an an area has equal votes, given the area and date in the procedure then display an equalvotes labeled column with a value of 50
Quite a few mistakes.
you don't need DECLARE within the named PL/SQL procedure
parameters names should differ from column names, so you'd rather use - for example - p_area in nvarchar2, p_dateofvote in date
if you select 3 columns, you have to put them INTO 3 variables - you've declared only one, so either declare two more, or remove AREA and DATEOFOTE from SELECT
what are those parameters used for? Usually, as a part of the WHERE clause - which is not the case in your code
pay attention to number of rows returned by the SELECT statement. If you're selecting into a scalar variable, make sure that it returns only one row
what will you do with TEST variable, once you get its value? Currently, nothing
you've got an END that is a surplus.
Therefore, consider something like this which should at least compile (depending on table description):
SQL> create table voting (area nvarchar2(10),
2 dateofvote date,
3 remainvotes nvarchar2(10),
4 leavevotes nvarchar2(10));
Table created.
SQL> create or replace procedure
2 sp_equalvote(p_area in nvarchar2, p_dateofvote in date)
3 is
4 test nvarchar2(255);
5 begin
6 select
7 case when remainvotes = leavevotes then remainvotes end
8 into test
9 from voting
10 where remainvotes = leavevotes
11 and area = p_area
12 and dateofvote = p_dateofvote;
13 end;
14 /
Procedure created.
SQL>
[EDIT]
After reading the comment, perhaps you'd rather use a function.
Some sample values:
SQL> insert into voting values (1, date '2019-02-20', 100, 15);
1 row created.
SQL> insert into voting values (1, date '2019-03-10', 300, 300);
1 row created.
Function:
SQL> create or replace function
2 sp_equalvote(p_area in nvarchar2, p_dateofvote in date)
3 return nvarchar2
4 is
5 test nvarchar2(255);
6 begin
7 select
8 case when remainvotes = leavevotes then 'draw'
9 else 'not equal'
10 end
11 into test
12 from voting
13 where area = p_area
14 and dateofvote = p_dateofvote;
15
16 return test;
17 end;
18 /
Function created.
SQL>
Testing:
SQL> select * From voting;
AREA DATEOFVOTE REMAINVOTE LEAVEVOTES
---------- ---------- ---------- ----------
1 20.02.2019 100 15
1 10.03.2019 300 300
SQL> select sp_equalvote(1, date '2019-02-20') res from dual;
RES
--------------------
not equal
SQL> select sp_equalvote(1, date '2019-03-10') res from dual;
RES
--------------------
draw
SQL>
DECLARE is not allowed in the body of a PL/SQL procedure. The IS or AS serves the purpose of delimiting where the variable declaration section starts - so your procedure should be
create or replace PROCEDURE sp_EqualVote(AREA IN NVARCHAR2, DATEOFVOTE IN DATE)
IS
test nvarchar(255);
BEGIN
SELECT
AREA,
DATEOFVOTE,
CASE
WHEN (REMAINVOTES = LEAVEVOTES) THEN REMAINVOTES
END AS EqualVote
INTO test
FROM VOTING
WHERE REMAINVOTES = LEAVEVOTES;
END;
You also had an extra END, which I removed.
Best of luck.

PLSQL function wont return salary where name of the employee is passed in as a parameter

Here is my PLSQL function:
Create or Replace FUNCTION getEmpSalary(p_name in VARCHAR)
Return NUMBER IS
l_return_salary;
l_salary;
table_salary NUMBER;
BEGIN
Select salary into table_salary from AlphaCoEmp where p_name = p_name;
return l_return_salary;
END;
/
show errors;
I have built a table that holds the following tuples:
NAME TITLE SALARY
------------------------- --------------------
Wong 91296
Utech 82058
Vega 86858
Weiser 79771
and am trying to write a PLSQL function to return the salary where the name is passed as parameter.
This is how I am passing as parameter: Note: param1 is the name chosen.
exec setEmpSalary(Utech);
I am getting the following error(s):
ERROR at line 1:
ORA-06550: line 1, column 20:
PLS-00201: identifier 'UTECH' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
I am unsure as to how this error is being created and could use some help fixing the error. Thanks for your time.
This is what you might/should have done:
First, a test case:
SQL> create table test
2 (ename varchar2(10),
3 salary number
4 );
Table created.
SQL> insert into test (ename, salary)
2 select 'Wong' , 91296 from dual union
3 select 'Utech', 82058 from dual;
2 rows created.
A function:
note the way I declared the parameter and the return value - both of them use the appropriate datatype of the column they reference
I used the MAX function when selecting the salary. Why? Because, if you pass an invalid employee name, function would return NO_DATA_FOUND error. Another - and probably a better way - is to handle that with the EXCEPTION section, such as
begin
select ...
exception
when no_data_found then return null;
end;
Though, MAX is a quick and dirty solution that saves you from some typing during the testing phase of your code.
SQL> create or replace function get_emp_salary(p_ename in test.ename%type)
2 return test.salary%type
3 is
4 retval test.salary%type;
5 begin
6 select max(t.salary)
7 into retval
8 from test t
9 where t.ename = p_ename;
10
11 return retval;
12 end;
13 /
Function created.
OK, let's see what it does:
SQL> select get_emp_salary('Utech') from dual;
GET_EMP_SALARY('UTECH')
-----------------------
82058
SQL> select get_emp_salary('Littlefoot') from dual;
GET_EMP_SALARY('LITTLEFOOT')
----------------------------
SQL>
Seems to be OK.
In your function, there are 3 local variables. The first two of them are invalidly declared (no datatype). SELECT then selects salary into "table_salary", but you're returning "l_return_salary" which is always NULL - why did you do that?
As of the error you got ("PLS-00201: identifier 'UTECH' must be declared"), it means that you passed the parameter value without single quotes, as you're passing employee name (which is a string).
Also, you're executing setEmpSalary, while the function is get (was it a typo?).
You have problem with your calling code -- UTECH needs to be declared -- or you need to put single quotes around it.
More importantly, the code for the function is wrong, because it confuses a parameter name and a column name.
I think you want:
Create or Replace FUNCTION getEmpSalary (in_p_name in VARCHAR)
Return NUMBER IS
l_return_salary NUMBER;
BEGIN
Select salary into l_return_salary
from AlphaCoEmp ace
where ace.p_name = in_p_name;
return(l_return_salary);
END;
Try
Create or Replace FUNCTION getEmpSalary(p_name in VARCHAR)
Return NUMBER IS
l_return_salary number;
BEGIN
Select salary
into l_return_salary
from AlphaCoEmp
where name = p_name;
return l_return_salary;
exception
when others then
return 0;
END;

SQL: No records found. Handling no errors found [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I created this SQL code because I need to rank an specific list of ISIN's. Therefore, I have been using the following code to get the results:
var r refcursor;
begin
msa.exl_stifel_ms ('01/01/2017',
'21/01/2018',
'GBP',
'CB',
'JE00BYR8GK67',
'UBS',
:r);
end;
and I get 'no records' found.. which is obviously wrong and indicates that's something wrong with the query.... any advice?
create or replace procedure msa.exl_stifel_ms (
tradedatestart in date,
tradedateend in date,
inccy in varchar,
inbtype in varchar,
invariable in varchar,
inbroker in varchar,
test out sys_refcursor)
as
inbrokerid integer;
begin
delete from tt_exl_out;
delete from isins_tt;
delete from tt_exl_indexdetail;
delete from index_tt;
select brokerid
into inbrokerid
from msa.client
where clientname = inbroker;
insert into isins_tt (isin)
select distinct effectiveisin
from msa.instrument inst
where inst.isin = invariable; --will need to loop through all the ISINs here
rp_calctrnbicdetailtotals (inccy,
inbtype,
tradedatestart,
tradedateend);
insert into tt_exl_indexdetail (isin,
brokerid,
brokercode,
brokertotal)
select i.effectiveisin,
ba.brokerid,
(select br2.brokercode
from broker br2
where br2.brokerid = ba.brokerid),
sum (t.total)
from bicisintotal_tt t
inner join bank ba
on t.bicid = ba.bicid and ba.includeinreport = 1
inner join instrument i on t.isin = i.isin
group by ba.brokerid, i.effectiveisin;
update tt_exl_indexdetail tt1
set percentage =
(select case x.totalvalue
when 0 then 0
else (i.brokertotal / x.totalvalue)
end
as percentage
from index_tt i,
(select sum (brokertotal) as totalvalue from index_tt) x
where brokerid = tt1.brokerid);
insert into tt_exl_out (yearno,
rank,
turnover,
marketshare)
select id1.brokerid,
dense_rank () over (order by id1.brokertotal desc),
id1.brokertotal,
id1.percentage
from index_tt id1;
open test for
select rank,
c.clientname,
turnover,
marketshare
from tt_exl_out tt3
inner join msa.client c on tt3.yearno = c.brokerid
where c.clientname = inbroker;
end;
Unless I'm wrong this:
select brokerid
into inbrokerid
from msa.client
where clientname = inbroker
is the only SELECT that could return NO-DATA-FOUND (if that's what you call "no records found"). Other SELECTs are part of INSERT or UPDATE statements, so they simply won't do anything, but won't raise an error either.
You also call rp_calctrnbicdetailtotals - I don't know what it does, but - it could be a candidate for an error as well.
Try to run that code in SQL*Plus, it'll tell you exact spot of an error (PL/SQL object name, line number) so you might be able to fix it. Make sure you remove all WHEN OTHERS exception handlers (if there are any).
[EDIT, after seeing #kfinity's comment]
As I said, I think not. Here's an example; the first SELECT returns nothing, there's no employee with EMPNO = -1 (so, as you said, it would return no-data-found):
SQL> var pe refcursor
SQL> create or replace procedure p_test (test out sys_refcursor) is
2 begin
3 open test for
4 select ename
5 from emp
6 where empno = -1;
7 end;
8 /
Procedure created.
SQL> exec p_test (:pe)
PL/SQL procedure successfully completed.
SQL> print pe
no rows selected
See? No error.
However, if it was an ordinary SELECT ... INTO, then yes - it would raise it:
SQL> create or replace procedure p_test as
2 l_ename varchar2(20);
3 begin
4 select ename into l_ename
5 from emp
6 where empno = -1;
7 end;
8 /
Procedure created.
SQL> exec p_test
BEGIN p_test; END;
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "HR.P_TEST", line 4
ORA-06512: at line 1
SQL>
[EDIT #2]
Yes, as Alessandro said, it should then be handled by the EXCEPTION section.

Arrays in Oracle SQL

Here's a simplified pseudo-code version of what I'd like to be able to do in PL-SQL (Oracle):
DECLARE
mylist as ARRAY
BEGIN
mylist (1) := '1'
mylist (2) := '3'
...
SELECT *
FROM aTable
WHERE aKey IN mylist;
END;
The SELECT should return the matching records for mylist(1), mylist(2) etc. It should be similar to ORing all the values, but of course we don't know in advance how many values we get.
How can I achieve this? I know that PL/SQL has some collection datatypes, but I can't seem to get them to work properly in SQL statements.
Thanks for any ideas.
This is easy to do with the TABLE() function. The one catch is that the array variable must use a type declared in SQL. This is because SELECT uses the SQL engine, so PL/SQL declarations are out of scope.
SQL> create or replace type numbers_nt as table of number
2 /
Type created.
SQL>
SQL> declare
2 l_array numbers_nt;
3 begin
4 l_array := numbers_nt (7521,7566,7654);
5 for r in ( select ename
6 from emp
7 where empno in ( select *
8 from table (l_array)
9 )
10 )
11 loop
12 dbms_output.put_line ( 'employee name = '||r.ename);
13 end loop;
14 end;
15 /
employee name = PADFIELD
employee name = ROBERTSON
employee name = BILLINGTON
PL/SQL procedure successfully completed.
SQL>
A couple of suggestions:
1.) There's a CAST SQL keyword that you can do that might do the job... it makes your collection be treated as if it were a table.
2.) Pipelined functions. Basically a function returns data that looks like a table.
This link summarises the options and has a number of code listings that explain them.
http://www.databasejournal.com/features/oracle/article.php/3352091/CASTing-About-For-a-Solution-Using-CAST-and-Table-Functions-in-PLSQL.htm