I am creating a procedure inside a package but getting below error while executing below script
CREATE PACKAGE doc_interface AS
code_value VARCHAR2(30 CHAR) ;
PROCEDURE list_doc (
lg_code IN fpl_ref.lang%TYPE,
pl_no IN prt_req.pl_no%TYPE,
cl_no IN prt_req.cl_no%TYPE,
ct_no IN prt_req.ct_no%TYPE,
potab_doc_list OUT custDocTab)
AS
BEGIN
potab_doc_list := NEW custDocTab();
IF pl_no IS NOT NULL AND cl_no IS NULL
THEN
select *
BULK COLLECT INTO potab_doc_list
from cs_record where req_id = 19736543;
END IF;
EXCEPTION
WHEN OTHERS
THEN
z_error ('Error while fetching records =' || SQLERRM);
END list_doc;
END doc_interface;
Error:
[Error] Syntax check (12: 0): ERROR line 13, col 1, ending_line 13, ending_col 5, Found 'BEGIN', Expecting: EXTERNAL LANGUAGE
Not understanding what it is expecting after instead of BEGIN.
The code you have shown, with `CREATE PACKAGE, is creating a package specification - but you have included the procedure body, which belong in the package body. You need to create the specification and body separately:
CREATE PACKAGE doc_interface AS
code_value VARCHAR2(30 CHAR) ;
PROCEDURE list_doc (
lg_code IN fpl_ref.lang%TYPE,
pl_no IN prt_req.pl_no%TYPE,
cl_no IN prt_req.cl_no%TYPE,
ct_no IN prt_req.ct_no%TYPE,
potab_doc_list OUT custDocTab);
END doc_interface;
/
then
CREATE PACKAGE BODY doc_interface AS
PROCEDURE list_doc (
lg_code IN fpl_ref.lang%TYPE,
pl_no IN prt_req.pl_no%TYPE,
cl_no IN prt_req.cl_no%TYPE,
ct_no IN prt_req.ct_no%TYPE,
potab_doc_list OUT custDocTab)
AS
BEGIN
potab_doc_list := NEW custDocTab();
IF pl_no IS NOT NULL AND cl_no IS NULL
THEN
select *
BULK COLLECT INTO potab_doc_list
from cs_record where req_id = 19736543;
END IF;
EXCEPTION
WHEN OTHERS
THEN
z_error ('Error while fetching records =' || SQLERRM);
END list_doc;
END doc_interface;
/
it isn't clear if you want the code_value declared in the package specification - where it will be public - or in the package body - where it will be private.
Read more about package structure:
A package always has a specification, which declares the public items that can be referenced from outside the package.
If the public items include cursors or subprograms, then the package must also have a body. The body must define queries for public cursors and code for public subprograms. The body can also declare and define private items that cannot be referenced from outside the package, but are necessary for the internal workings of the package.
Also read about package state if you do have/need spec-level variables.
You don't put implementation code in the PACKAGE (SPEC), you define that in the PACKAGE BODY.
Also, if you put CODE_VALUE in the body vs the spec, you won't be able to reference it outside the package.
So more like -
CREATE PACKAGE DOC_INTERFACE AS
code_value VARCHAR2(30 CHAR) ;
PROCEDURE list_doc (
lg_code IN fpl_ref.lang%TYPE,
pl_no IN prt_req.pl_no%TYPE,
cl_no IN prt_req.cl_no%TYPE,
ct_no IN prt_req.ct_no%TYPE,
potab_doc_list OUT custDocTab);
END DOC_INTERFACE;
/
CREATE PACKAGE BODY doc_interface AS
PROCEDURE list_doc (
lg_code IN fpl_ref.lang%TYPE,
pl_no IN prt_req.pl_no%TYPE,
cl_no IN prt_req.cl_no%TYPE,
ct_no IN prt_req.ct_no%TYPE,
potab_doc_list OUT custDocTab)
AS
BEGIN
potab_doc_list := NEW custDocTab();
IF pl_no IS NOT NULL AND cl_no IS NULL
THEN
select *
BULK COLLECT INTO potab_doc_list
from cs_record where req_id = 19736543;
END IF;
EXCEPTION
WHEN OTHERS
THEN
z_error ('Error while fetching records =' || SQLERRM);
END list_doc;
END doc_interface;
/
Related
Have been searching for ages to no avail. Part of an assessment it specifies that we must declare a public variable WITHIN a package (so don't try telling me to make it a stand alone function...) that is the number of rows from another table ("SELECT COUNT(*) FROM A2_GUESTS" is the hint)
I can set a public variable easily enough as a static number, however if i try to add the select statement it throws an error.
If I try to assign it in the package body then it also throws an error, if I wrap it within "begin" and "end" it terminates the package body too early.
CREATE OR REPLACE PACKAGE Beachcomber
AS
v_Guest_Count NUMBER := 0;
END Beachcomber;
/
CREATE OR REPLACE PACKAGE BODY Beachcomber IS
SELECT COUNT(*) INTO v_Guest_Count FROM A2_GUESTS; -- doesn't work
v_Guest_Count NUMBER := SELECT COUNT(*) FROM A2_GUESTS; -- doesn't work
BEGIN
v_Guest_Count NUMBER := SELECT COUNT(*) FROM A2_GUESTS;
END; -- doesn't work - ends the package prematurely
END Beachcomber;
the above example are the ways i've been trying (amongst others), not at the same time but individually.
We get given the code to test it: (must not change this testing code)
PROMPT
PROMPT TESTING: Initialisation of the v_Guest_Count variable. Expect 81.
BEGIN
DBMS_OUTPUT.PUT_LINE('v_Guest_Count has been initialised to: '||TO_CHAR(BEACHCOMBER.v_Guest_Count));
END;
any help is greatly appreciated, i found someone asked this here once back in 2015 but the only answer was given as make it a function and they adjusted the testing code so thats less than helpful.
there is more code within the package with procedures and functions:
CREATE OR REPLACE PACKAGE Beachcomber
IS
v_Guest_Count NUMBER := 0;
PROCEDURE ADD_GUEST
(p_guest_name A2_GUESTS.guest_name%TYPE,
p_guest_address A2_GUESTS.guest_address%TYPE);
END Beachcomber;
/
CREATE OR REPLACE PACKAGE BODY Beachcomber IS
BEGIN
SELECT COUNT(*) INTO v_Guest_Count FROM A2_GUESTS;
PROCEDURE ADD_GUEST
(p_guest_name A2_GUESTS.guest_name%TYPE,
p_guest_address A2_GUESTS.guest_address%TYPE)
IS BEGIN
INSERT INTO A2_GUESTS (Guest_ID, Guest_Name, Guest_Address)
VALUES (guest_id_seq.NEXTVAL, p_guest_name, p_guest_address);
v_Guest_Count := v_Guest_Count +1;
END ADD_GUEST;
END Beachcomber;
this will throw:
5/5 PLS-00103: Encountered the symbol "PROCEDURE" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge The symbol "declare" was substituted for "PROCEDURE" to continue.
im normally alright with working it out from the error messages but oracle error messages may as well be written in dutch to me :/
We can include initialising code in a package by putting it at the end of the body. It takes the form of a BEGIN block which is terminated by the final END of the package body.
create or replace package BEACHCOMBER is
v_Guest_Count pls_integer;
function get_cnt return number;
end BEACHCOMBER;
/
create or replace package body BEACHCOMBER is
function get_cnt return number
is
begin
return v_Guest_Count;
end get_cnt;
<< init_block >>
begin
select count(*)
into v_Guest_Count
from A2_GUESTS;
end BEACHCOMBER;
/
The code under the label << init_block >> is run the first time the package is invoked. This includes referencing the public variable. This code not run again in the session, unless the package is recompiled, which discards state.
Here is my test script. I have published this as a working demo on Oracle LiveSQL (because DBMS_OUTPUT) but you need a free Oracle account to run it. Check it out
Test set up
drop table A2_GUESTS
/
create table A2_GUESTS (id number);
insert into A2_GUESTS select level from dual connect by level <=23;
create or replace package BEACHCOMBER is
v_Guest_Count pls_integer;
function get_cnt return number;
end BEACHCOMBER;
/
create or replace package body BEACHCOMBER is
function get_cnt return number
is
begin
return v_Guest_Count;
end get_cnt;
begin
select count(*)
into v_Guest_Count
from A2_GUESTS;
end BEACHCOMBER;
/
Here are the tests;
begin
dbms_output.put_line('count = ' || BEACHCOMBER.v_Guest_Count);
end;
/
insert into A2_GUESTS values (42)
/
select BEACHCOMBER.get_cnt
from dual
/
alter package BEACHCOMBER compile body
/
select BEACHCOMBER.get_cnt
from dual
/
You have to set the Package variable in the package body. You need not declare another variable locally in the body.
CREATE OR REPLACE PACKAGE BODY Beachcomber IS
BEGIN
SELECT COUNT(*) INTO v_Guest_Count FROM A2_GUESTS;
END Beachcomber;
/
You may then access that variable in any other PL/SQL block.
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE(Beachcomber.v_Guest_Count);
end;
/
0
PL/SQL procedure successfully completed.
EDIT
You should put the queries inside the procedure as you would be calling the procedure externally.
CREATE OR REPLACE PACKAGE BODY beachcomber IS
PROCEDURE add_guest (
p_guest_name a2_guests.guest_name%TYPE,
p_guest_address a2_guests.guest_address%TYPE
)
IS
BEGIN
SELECT COUNT(*)
INTO v_guest_count
FROM a2_guests;
INSERT INTO a2_guests (
guest_id,
guest_name,
guest_address
) VALUES (
guest_id_seq.NEXTVAL,
p_guest_name,
p_guest_address
);
v_guest_count := v_guest_count + 1;
END add_guest;
END beachcomber;
/
EDIT2 : using a main procedure for initialisation.
CREATE OR REPLACE PACKAGE beachcomber IS
v_guest_count NUMBER := 0;
PROCEDURE main;
PROCEDURE add_guest (
p_guest_name a2_guests.guest_name%TYPE,
p_guest_address a2_guests.guest_address%TYPE
);
END beachcomber;
/
CREATE OR REPLACE PACKAGE BODY beachcomber IS
PROCEDURE add_guest (
p_guest_name a2_guests.guest_name%TYPE,
p_guest_address a2_guests.guest_address%TYPE
)
IS
BEGIN
INSERT INTO a2_guests (
guest_id,
guest_name,
guest_address
) VALUES (
guest_id_seq.NEXTVAL,
p_guest_name,
p_guest_address
);
v_guest_count := v_guest_count + 1;
END add_guest;
PROCEDURE main
IS
BEGIN
SELECT COUNT(*)
INTO v_guest_count
FROM a2_guests;
END main;
END beachcomber;
/
Execution of procedure.
BEGIN
beachcomber.main;
beachcomber.add_guest('Sherlock','221b baker street');
END;
/
I am trying to create a new package, but I get the ORA-24344: success with compilation error and I cannot figure out what is the problem.
Here is my code:
CREATE OR REPLACE PACKAGE BODY lucratori_pack AS
CURSOR disp_lucrator RETURN LucratorRecType IS
SELECT ID_LUCRATOR, NUME_LUCRATOR, PRENUME_LUCRATOR, SALARIUL FROM LUCRATORI ORDER BY SALARIUL;
PROCEDURE increase_sal(
emp_id LUCRATORI.ID_LUCRATOR%type,
emp_inc_sal LUCRATORI.SALARIUL%type
)
IS
emp_new_sal LUCRATORI.SALARIUL%type;
BEGIN
UPDATE LUCRATORI
SET SALARIUL = SALARIUL + emp_inc_sal
WHERE LUCRATORI.id_lucrator = emp_id
returning SALARIUL INTO emp_new_sal;
END increase_sal;
PROCEDURE getAllEmps
IS
CURSOR c is
SELECT NUME_LUCRATOR, PRENUME_LUCRATOR FROM LUCRATORI;
c_nume LUCRATORI.NUME_LUCRATOR%type;
c_prenume LUCRATORI.PRENUME_LUCRATOR%type;
BEGIN
open c;
loop
EXIT WHEN c%NOTFOUND;
fetch c INTO c_nume, c_prenume;
dbms_output.put_line('Numele: ' || c_nume || ' Prenumele: ' || c_prenume);
end loop;
close c;
END getAllEmps;
END lucratori_pack;
I have tested the procedures, and they do not contain errors. Below is the code for the table I am using in the 2 procedures declared inside the package:
CREATE TABLE Lucratori (
id_lucrator varchar2(5) constraint pk_lucrator primary key,
nume_lucrator varchar2(30),
prenume_lucrator varchar2(30),
data_nasterii date,
salariul number(5),
pozitia_ocupata varchar2(40),
id_companie varchar2(5),
constraint fk_lucrator_companie foreign key (id_companie)
references Companii(id_companie)
);
Firstly, it's the wrong place for a cursor definition, the place just after PACKAGE BODY definition , where some global parameters may be defined. And, that cursor (disp_lucrator) is used nowhere. Then Just remove that :
CREATE OR REPLACE PACKAGE lucratori_pack AS
PROCEDURE increase_sal(emp_id LUCRATORI.ID_LUCRATOR%type,
emp_inc_sal LUCRATORI.SALARIUL%type);
PROCEDURE getAllEmps;
END lucratori_pack;
/
CREATE OR REPLACE PACKAGE BODY lucratori_pack AS
/* CURSOR disp_lucrator RETURN LucratorRecType IS
SELECT ID_LUCRATOR, NUME_LUCRATOR, PRENUME_LUCRATOR, SALARIUL FROM LUCRATORI ORDER BY SALARIUL;*/
PROCEDURE increase_sal(
emp_id LUCRATORI.ID_LUCRATOR%type,
emp_inc_sal LUCRATORI.SALARIUL%type
)
IS
emp_new_sal LUCRATORI.SALARIUL%type;
BEGIN
UPDATE LUCRATORI
SET SALARIUL = SALARIUL + emp_inc_sal
WHERE LUCRATORI.id_lucrator = emp_id
returning SALARIUL INTO emp_new_sal;
END increase_sal;
PROCEDURE getAllEmps
IS
CURSOR c is
SELECT NUME_LUCRATOR, PRENUME_LUCRATOR FROM LUCRATORI;
c_nume LUCRATORI.NUME_LUCRATOR%type;
c_prenume LUCRATORI.PRENUME_LUCRATOR%type;
BEGIN
open c;
loop
EXIT WHEN c%NOTFOUND;
fetch c INTO c_nume, c_prenume;
dbms_output.put_line('Numele: ' || c_nume || ' Prenumele: ' || c_prenume);
end loop;
close c;
END getAllEmps;
END lucratori_pack;
/
I am writing a function and i want to wrap it with table function so i can use with select query.
Here is my type declaration and the some lines of my functions
CREATE OR REPLACE PACKAGE TYPES
AS
TYPE CURSORTYPE IS REF CURSOR;
TYPE vbugsrec
IS
RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE vbugstable
IS
TABLE OF vbugsrec
INDEX BY BINARY_INTEGER;
END;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN types.vbugstable
IS
datarows types.vbugstable;
var_useralias userpass.ldapalias%TYPE
:= UPPER (pendverifylist.myldapid) ;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO pendverifylist.datarows
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/
When i want to use TABLE function like below, i get error.ORA-00902: invalid datatype
SELECT * FROM TABLE(CUSTOMQUERIES.PENDVERIFYLIST ( 'product', 50 ));
Can anyone please help what i am doing wrong here?
Thanks in advance
You're trying to use package-level types in plain SQL, which isn't allowed. The types declared in the package are not visible to or valid outside PL/SQL (or even in plain SQL statements within PL/SQL). A cut-down version of what you're doing:
create or replace package types as
type my_rec_type is record (dummy dual.dummy%type);
type my_table_type is table of my_rec_type index by binary_integer;
end types;
/
create or replace package p42 as
function get_table return types.my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return types.my_table_type is
my_table types.my_table_type;
begin
select * bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
SQL Error: ORA-00902: invalid datatype
Even within the package, if you had a procedure that tried to use the table function it would error. If you added:
procedure test_proc is
begin
for r in (select * from table(get_table)) loop
null;
end loop;
end test_proc;
... the package body compilation would fail with ORA-22905: cannot access rows from a non-nested table item.
You need to declare the types at schema level, not in a package, so using the SQL create type command:
create type my_obj_type is object (dummy varchar2(1));
/
create type my_table_type is table of my_obj_type;
/
create or replace package p42 as
function get_table return my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return my_table_type is
my_table my_table_type;
begin
select my_obj_type(dummy) bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
DUMMY
-----
X
Actually tehere is not need to have types in schema level. All you need to do is to define function as PIPELINED.
-- DEFINITION IN PCKG HEADER
create or replace PACKAGE "AAA" IS
TYPE t_record IS RECORD (
aaa VARCHAR(20 CHAR),
bbb VARCHAR(50 CHAR),
ccc VARCHAR(10 CHAR)
);
TYPE t_collection is table of t_record;
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED;
END AAA;
-- PCKG BODY
create or replace PACKAGE BODY AAA AS
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED AS
CURSOR k1 is SELECT aaa,bbb,ccc FROM table;
BEGIN
FOR rec IN k1
LOOP
pipe row( (rec) );
END LOOP;
END get_records
END AAA;
-- CALLING FUNCTION OUTSIDE OF PCKG
select * from TABLE(AAA.get_records(par1, par2));
Thanks to Alex Poole. This is what i ended up with
CREATE OR REPLACE TYPE vbugsrec
IS
OBJECT (
bug_id NUMBER(9),
facility VARCHAR2(256)
);
CREATE OR REPLACE TYPE vbugstable
IS
TABLE OF vbugsrec;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN vbugstable
IS
datarows vbugstable := vbugstable();
var_useralias userpass.ldapalias%TYPE:= UPPER (pendverifylist.myldapid) ;
TYPE temp_rec IS RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE temp_records
IS
TABLE OF temp_rec
INDEX BY BINARY_INTEGER;
temporary_records temp_records;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO temporary_records
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
IF temporary_records.COUNT <> 0
THEN
FOR rec_idx IN temporary_records.FIRST .. temporary_records.LAST
LOOP
datarows.EXTEND;
datarows (datarows.LAST) :=
vbugsrec (temporary_records (rec_idx).bug_id,
temporary_records (rec_idx).facility);
END LOOP;
END IF;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/
I am writing a function and i want to wrap it with table function so i can use with select query.
Here is my type declaration and the some lines of my functions
CREATE OR REPLACE PACKAGE TYPES
AS
TYPE CURSORTYPE IS REF CURSOR;
TYPE vbugsrec
IS
RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE vbugstable
IS
TABLE OF vbugsrec
INDEX BY BINARY_INTEGER;
END;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN types.vbugstable
IS
datarows types.vbugstable;
var_useralias userpass.ldapalias%TYPE
:= UPPER (pendverifylist.myldapid) ;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO pendverifylist.datarows
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/
When i want to use TABLE function like below, i get error.ORA-00902: invalid datatype
SELECT * FROM TABLE(CUSTOMQUERIES.PENDVERIFYLIST ( 'product', 50 ));
Can anyone please help what i am doing wrong here?
Thanks in advance
You're trying to use package-level types in plain SQL, which isn't allowed. The types declared in the package are not visible to or valid outside PL/SQL (or even in plain SQL statements within PL/SQL). A cut-down version of what you're doing:
create or replace package types as
type my_rec_type is record (dummy dual.dummy%type);
type my_table_type is table of my_rec_type index by binary_integer;
end types;
/
create or replace package p42 as
function get_table return types.my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return types.my_table_type is
my_table types.my_table_type;
begin
select * bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
SQL Error: ORA-00902: invalid datatype
Even within the package, if you had a procedure that tried to use the table function it would error. If you added:
procedure test_proc is
begin
for r in (select * from table(get_table)) loop
null;
end loop;
end test_proc;
... the package body compilation would fail with ORA-22905: cannot access rows from a non-nested table item.
You need to declare the types at schema level, not in a package, so using the SQL create type command:
create type my_obj_type is object (dummy varchar2(1));
/
create type my_table_type is table of my_obj_type;
/
create or replace package p42 as
function get_table return my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return my_table_type is
my_table my_table_type;
begin
select my_obj_type(dummy) bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
DUMMY
-----
X
Actually tehere is not need to have types in schema level. All you need to do is to define function as PIPELINED.
-- DEFINITION IN PCKG HEADER
create or replace PACKAGE "AAA" IS
TYPE t_record IS RECORD (
aaa VARCHAR(20 CHAR),
bbb VARCHAR(50 CHAR),
ccc VARCHAR(10 CHAR)
);
TYPE t_collection is table of t_record;
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED;
END AAA;
-- PCKG BODY
create or replace PACKAGE BODY AAA AS
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED AS
CURSOR k1 is SELECT aaa,bbb,ccc FROM table;
BEGIN
FOR rec IN k1
LOOP
pipe row( (rec) );
END LOOP;
END get_records
END AAA;
-- CALLING FUNCTION OUTSIDE OF PCKG
select * from TABLE(AAA.get_records(par1, par2));
Thanks to Alex Poole. This is what i ended up with
CREATE OR REPLACE TYPE vbugsrec
IS
OBJECT (
bug_id NUMBER(9),
facility VARCHAR2(256)
);
CREATE OR REPLACE TYPE vbugstable
IS
TABLE OF vbugsrec;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN vbugstable
IS
datarows vbugstable := vbugstable();
var_useralias userpass.ldapalias%TYPE:= UPPER (pendverifylist.myldapid) ;
TYPE temp_rec IS RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE temp_records
IS
TABLE OF temp_rec
INDEX BY BINARY_INTEGER;
temporary_records temp_records;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO temporary_records
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
IF temporary_records.COUNT <> 0
THEN
FOR rec_idx IN temporary_records.FIRST .. temporary_records.LAST
LOOP
datarows.EXTEND;
datarows (datarows.LAST) :=
vbugsrec (temporary_records (rec_idx).bug_id,
temporary_records (rec_idx).facility);
END LOOP;
END IF;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/
I am working on this for my homework. When I run it, I get the error:
PACKAGE PKG_Q4 Compiled.
Warning: execution completed with warning
PACKAGE BODY PKG_Q4 Compiled.
50/12 PLS-00330: invalid use of type name or subtype name.
I've looked into this but I cant seem to find a way to fix it. It is pointing to this line:
INTO v_Room_Number, v_Pet_Status, v_Customer_Source_Description, v_Invoice_Total
Here is my code:
CREATE OR REPLACE PACKAGE BODY PKG_Q4
AS
FUNCTION FN_Q4
(p_First_Name VARCHAR2, p_Last_Name VARCHAR2)
RETURN VARCHAR2
AS
v_Output VARCHAR2(500);
v_Room_Number NUMBER(3,0);
v_Pet_Status CHAR(1);
v_Customer_Source_Description VARCHAR2(30);
v_Invoice_Total NUMBER(7,2);
v_First_Name VARCHAR2(15);
v_Last_Name VARCHAR2(20);
v_Customer_Code CHAR(4);
v_Registration_Status_Code CHAR(1);
BEGIN
SELECT First_Name, Last_Name
INTO v_First_Name, v_Last_Name
FROM Customer
WHERE First_Name = p_First_Name AND
Last_Name = p_Last_Name;
Select Registration_Status_Code
INTO v_Registration_Status_Code
FROM Registration_Status;
IF v_Registration_Status_Code = 'N' THEN
SELECT Room.Room_Number, Room.Pet_Status, Customer_Source.Customer_Source_Description, Invoice.Invoice_Total
INTO v_Room_Number, v_Pet_Status, v_Customer_Source_Description, v_Invoice_Total
FROM Registration , Customer , Customer_Source , Room , Invoice
WHERE Customer.customer_code = Registration.customer_code AND
Customer_Source.customer_source_code = Customer.customer_source_code AND
Room.room_number = Registration.room_number AND
Registration.registration_number = Invoice.registration_number;
v_Output := 'Room Number:' || v_Room_Number ||'Pet Status:' || v_Pet_Status ||
'Customer Source Code:' || v_Customer_Source_Description ||'Total Cost:' || v_Invoice_Total;
END IF;
Return Varchar2;
I'd wager the problem is actually this line, at the very bottom of the code excerpt:
Return Varchar2;
"Varchar2" is a type, you can't use it as the argument of a RETURN statement. In the function declaration, RETURN VARCHAR2 is correct usage, indicating the type of the value returned by the function. The actual RETURN statement should return a value of that type, like
RETURN 'This is a string literal';
In your case, I'm guessing you want:
RETURN v_Output;