This function is inside a package, but when I call the function the following error appears: PL/SQL "all_search" is not a procedure or is undefined. Someone can help me?
CREATE OR REPLACE PACKAGE employee_tab IS
FUNCTION all_search (ID_EMP in NUMBER) RETURN O_T_EMPL PIPELINED;
END employee_tab;
/
CREATE OR REPLACE TYPE O_T_EMPL AS TABLE OF O_EMPLOYEE;
/
CREATE OR REPLACE PACKAGE BODY employee_tab IS
FUNCTION all_search (ID_EMP in NUMBER) RETURN O_T_EMPL PIPELINED
IS
TAB_OBJC_EMP O_T_EMPL;
MY_QUERY_SEARCH VARCHAR2(400);
REF_C SYS_REFCURSOR;
MAX_ROW NUMBER := 25;
BEGIN
MY_QUERY_SEARCH := 'SELECT *
FROM EMPLOYEES
WHERE EMPLOYEE_ID = ID_EMP';
open REF_C for MY_QUERY_SEARCH using ID_EMP;
loop
--
fetch REF_C bulk collect into TAB_OBJC_EMP limit MAX_ROW;
exit when TAB_OBJC_EMP.count = 0;
for i in 1..TAB_OBJC_SEE.count
--
loop
pipe row(O_EMPLOYEE(TAB_OBJC_EMP(i).V_O_EMP_ID,
TAB_OBJC_EMP(i).V_O_HIRE_ID,
TAB_OBJC_EMP(i).V_O_DEP_ID)
);
end loop;
--
END loop;
--
CLOSE REF_C;
RETURN;
--
END all_search;
END employee_tab;
/
call function: employee_tab.all_search(1);
You need to assign the result of the function to something, try something like:
DECLARE
l_emp_id NUMBER;
BEGIN
SELECT EMP_ID
INTO l_emp_id
FROM TABLE(employee_tab.all_search(1))
WHERE rownum = 1;
DBMS_OUTPUT.put_line(TO_CHAR(EMP_ID));
END;
/
I'm working on a PLSQL package that calls another PLSQL package that returns separated results (i.e OUT variables) as follows:
(1) SYS_REFCURSOR
(1) NUMBER
(1) VARCHAR2
This is the dbfiddle I build.
Full code of the linked dbfiddle:
/* Main table - it contains the data to use in a cursor: */
CREATE TABLE tpos_retbenf
(
id_serial NUMBER (9,0),
serial_nmb NUMBER(12,0)
);
/* Destination of the records detected on "tpos_retbenf": */
CREATE TABLE tbl_debug
(
msg_text VARCHAR2(1000),
record_date DATE
);
/* Add values to the main table: */
INSERT INTO tpos_retbenf (id_serial, serial_nmb)
VALUES (1, 202108311635);
/* Package that contains the code to execute: */
create or replace PACKAGE PCK_POS_UNO is
PROCEDURE SP_POS_UNO (ID_RECORD IN NUMBER,
CUR_RET_BENF OUT SYS_REFCURSOR,
IDERROR OUT NUMBER,
DSERROR OUT VARCHAR2);
end PCK_POS_UNO;
/
create or replace PACKAGE BODY PCK_POS_UNO is
/* This is the procedure that returns results in separated variables: */
PROCEDURE SP_POS_UNO (ID_RECORD IN NUMBER,
CUR_RET_BENF OUT SYS_REFCURSOR,
IDERROR OUT NUMBER,
DSERROR OUT VARCHAR2) AS
v_temp number(6) := 0;
v_S varchar2(1) := 'S';
BEGIN
if ID_RECORD is null or ID_RECORD <= 0 then
IDERROR := -1;
DSERROR := 'Id no valido para la operacion';
goto finalizar;
end if;
select count(1) into v_temp
from tpos_retbenf r
where r.id_serial = ID_RECORD;
if v_temp = 0 then
IDERROR := -1;
DSERROR := 'Id no encontrado';
goto finalizar;
end if;
OPEN CUR_RET_BENF FOR
select r.id_serial, r.serial_nmb
from tpos_retbenf r
where r.id_serial = ID_RECORD;
<<finalizar>>
null;
END SP_POS_UNO;
END PCK_POS_UNO;
/
/* Package that calls the "SP_POS_UNO" procedure from the "PCK_POS_UNO" package: */
create or replace PACKAGE PKG_BH_ONLINE_INFORMATION IS
PROCEDURE ONLINENOVELTYBEN
(
V_NID_DEV IN NUMBER,
CV_1 IN OUT SYS_REFCURSOR
);
END PKG_BH_ONLINE_INFORMATION;
/
create or replace PACKAGE BODY PKG_BH_ONLINE_INFORMATION IS
PROCEDURE ONLINENOVELTYBEN
(
V_NID_DEV IN NUMBER,
CV_1 IN OUT SYS_REFCURSOR
) IS
V_USER VARCHAR2(10 CHAR) := 'INTERNET';
V_QUERY VARCHAR2(10000 CHAR);
-- Variables:
V_OUT_CUR_RET_BENF SYS_REFCURSOR;
V_OUT_IDERROR NUMBER;
V_OUT_DSERROR VARCHAR2(10000 CHAR);
BEGIN
/*
Here, the "PCK_POS_UNO.SP_POS_UNO" is called
from "PKG_BH_ONLINE_INFORMATION" as follows:
*/
V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
EXECUTE IMMEDIATE V_QUERY INTO V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR USING V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR ;
/*
An this error occurs:
Error: ORA-00904: "PCK_POS_UNO"."SP_POS_UNO": invalid identifier - StackTrace: ORA-06512: in line 24
*/
-- After getting the results in (V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR) variables,
-- a LOOP is executed for retrieve the records in "V_OUT_CUR_RET_BENF" cursor...
-- It doesn't continue here due to error shown above.
END ONLINENOVELTYBEN;
END PKG_BH_ONLINE_INFORMATION;
/
When the following code is going to be executed:
V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
EXECUTE IMMEDIATE V_QUERY INTO V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR USING V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR ;
The error says:
Error: ORA-00904: "APPLICATION_POS"."PCK_POS_UNO"."SP_POS_UNO": invalid identifier -
StackTrace: ORA-06512: in line 24
I've tried so far:
Search for ORA-00904 error - in this answer says "proper permissions on objects involved in the query" - which I share, but, I don't know how to argument this option (since I can do a simple SELECT to that table and the results are shwon, hence, they might not accept this argument). Related to this argument, I can't get listed the PCK_POS_UNO package "since the OWNER is different from the one I'm usually using (that is APPLICATION)".
I made a copy of this package/procedure and was able to execute the procedure/package via SQL Developer - see screenshot, but, the same error ORA-00904 occurs.
Screentshot of the execution of the package:
Results:
Change the code that calls the procedure that has OUT parameters, but, I'm unable to get a successful combination that allows the compilation and execution of the code as a whole.
Examples - all based on internet searchs and my own "instinct":
(1): Added (;) at the end of the dynamic-sql string:
V_QUERY := 'SELECT APPLICATION_POS.PCK_POS_UNO.SP_POS_UNO((:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL;';
(2): Removing the OWNER - in this case "APPLICATION_POS":
V_QUERY := 'SELECT PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR) FROM DUAL';
(3): Calling the procedure directly - it shows SP2-0552: bind variable "V_NID_DEV" not declared - but, how?, in a separated sample, the variable "V_NID_DEV" is declared and with value "2462013":
PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR);
(4): Calling the procedure directly (removing also the points) - in this case, ORA-01001 - invalid cursor error is generated - which I think it doesn't make sense - since the OUT cursor is not being opened for read or operated somehow.
PCK_POS_UNO.SP_POS_UNO(V_NID_DEV, V_OUT_CUR_RET_BENF, V_OUT_IDERROR, V_OUT_DSERROR);
I'm really run out of ideas - since I'm not familiar with this type of creating packages and passing values between packages and I didn't created this code.
Is there any way to make this code work?
Package modified to call procedure SP_POS_UNO:
CREATE OR REPLACE PACKAGE BODY PKG_BH_ONLINE_INFORMATION
IS
PROCEDURE ONLINENOVELTYBEN(V_NID_DEV IN NUMBER,
CV_1 IN OUT SYS_REFCURSOR
)
IS
V_USER VARCHAR2(10 CHAR) := 'INTERNET';
V_QUERY VARCHAR2(10000 CHAR);
-- Variables:
V_OUT_CUR_RET_BENF SYS_REFCURSOR;
V_OUT_IDERROR NUMBER;
V_OUT_DSERROR VARCHAR2(10000 CHAR);
BEGIN
/*
Here, the "PCK_POS_UNO.SP_POS_UNO" is called
from "PKG_BH_ONLINE_INFORMATION" as follows:
*/
V_QUERY:='Begin
PCK_POS_UNO.SP_POS_UNO(:V_NID_DEV, :V_OUT_CUR_RET_BENF, :V_OUT_IDERROR, :V_OUT_DSERROR);
End;';
--
EXECUTE IMMEDIATE V_QUERY
USING V_NID_DEV,
out V_OUT_CUR_RET_BENF,
out V_OUT_IDERROR,
out V_OUT_DSERROR ;
Dbms_Output.Put_Line('V_OUT_IDERROR='||V_OUT_IDERROR);
Dbms_Output.Put_Line('V_OUT_DSERROR='||V_OUT_DSERROR);
--
CV_1:=V_OUT_CUR_RET_BENF;
END ONLINENOVELTYBEN;
--
END PKG_BH_ONLINE_INFORMATION;
Currently, I'm working on creating a stored procedure that I can pass a list of strings to from my C# application using a DataReader. So part of it is also properly declaring that Associative Array so the stored procedure can accept the data.
Here is what I currently have (I'm not too concerned about the C# side of things at the moment):
CREATE OR REPLACE PACKAGE TEST_PACKAGE_01
AS
TYPE t_string_list is table of VARCHAR2(4000) index by pls_integer;
PROCEDURE SP_TEST_01(in_list IN t_string_list, out_cursor OUT SYS_REFCURSOR);
END TEST_PACKAGE_01;
/
CREATE OR REPLACE PACKAGE BODY TEST_PACKAGE_01
AS
PROCEDURE SP_TEST_01(in_list IN t_string_list, out_cursor OUT SYS_REFCURSOR)
IS
BEGIN
OPEN out_cursor;
FORALL indx IN 1..in_list.COUNT
-- I have tried numerous different things here with no success, this is just what I have in my latest iteration
INSERT INTO out_cursor Values (SELECT * FROM SOME_TABLE WHERE SOME_COLUMN = in_list(indx));
CLOSE out_cursor;
END SP_TEST_01;
END TEST_PACKAGE_01;
Within the body of the procedure, I managed to get it to return a SYS_REFCURSOR just fine, albeit just a test without any input. Something kind of like:
OPEN out_cursor FOR
SELECT * FROM SOME_TABLE;
I can't use a simple IN statement for the query against SOME_TABLE since in_list can potentially contain thousands of records. Ideally, I'd like to populate out_cursor with one statement, instead of performing a loop.
Cursors are pretty new territory for me, so maybe it isn't possible to do what I'm thinking with them, but I haven't seen anything to the contrary.
In 11g you can't access the PL/SQL table type from SQL, even if that SQL is within a PL/SQL block. You can create a schema-level type instead:
CREATE OR REPLACE TYPE t_string_list AS TABLE OF VARCHAR2(4000)
/
Then your package becomes:
CREATE OR REPLACE PACKAGE TEST_PACKAGE_01
AS
PROCEDURE SP_TEST_01(in_list IN t_string_list, out_cursor OUT SYS_REFCURSOR);
END TEST_PACKAGE_01;
/
CREATE OR REPLACE PACKAGE BODY TEST_PACKAGE_01
AS
PROCEDURE SP_TEST_01(in_list IN t_string_list, out_cursor OUT SYS_REFCURSOR)
IS
BEGIN
OPEN out_cursor FOR
SELECT *
FROM SOME_TABLE
WHERE SOME_COLUMN IN (
SELECT * FROM TABLE(in_list)
);
END SP_TEST_01;
END TEST_PACKAGE_01;
/
or with a join instead of IN:
CREATE OR REPLACE PACKAGE BODY TEST_PACKAGE_01
AS
PROCEDURE SP_TEST_01(in_list IN t_string_list, out_cursor OUT SYS_REFCURSOR)
IS
BEGIN
OPEN out_cursor FOR
SELECT st.*
FROM TABLE(in_list) t
JOIN SOME_TABLE st ON st.SOME_COLUMN = t.COLUMN_VALUE;
END SP_TEST_01;
END TEST_PACKAGE_01;
/
The TABLE() is a table collection expression.
db<>fiddle with made-up table and anonymous block to test.
I have a type like this ...
CREATE OR REPLACE TYPE TYPE_X
AS
TABLE OF VARCHAR2(4000);
... which is used in a package:
CREATE OR REPLACE PACKAGE PACKAGE_TEST
AS
TYPE DETAILS
IS
RECORD
(
EMPNO NUMBER,
ENAME VARCHAR2(4000),
DEPTNO NUMBER );
TYPE DETAILS_ARRAY
IS
TABLE OF DETAILS;
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY );
END;
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
AS
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY )
AS
BEGIN
FOR I IN 1..X.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(X(I));
SELECT EMPNO,ENAME,DEPTNO INTO Y FROM EMP WHERE DEPTNO=X(I);
END LOOP;
END;
END;
I'd like to print the data into the record type by executing all the values from the TYPE_X list. The data needs to be appended till the loop exits. Appreciate your help. Thanks!!
The approach which requires the least change to your existing code would be to populate a local variable of the record type, then append that to the OUT array.
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
AS
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY )
AS
l_rec DETAILS;
BEGIN
-- initialize output array
y := package_test.details_array();
FOR I IN 1..X.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(X(I));
SELECT EMPNO,ENAME,DEPTNO INTO lrec
FROM EMP
WHERE DEPTNO=X(I);
y.extend();
y(y.count) := lrec;
END LOOP;
END;
END;
This would be inefficient for a large number of rows. In that case you should look to use BULK COLLECT instead:
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
AS
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY )
AS
l_rec DETAILS;
BEGIN
SELECT EMPNO,ENAME,DEPTNO
bulk collect INTO y
FROM EMP
WHERE DEPTNO in ( select * from table (X));
END;
END;
the Exercise is:
Create a public variable in a package called v_Guest_Count
that is automatically initialised with the number of
Guests in the Guests table. Use the following SQL:
SELECT COUNT(*)
FROM Guests;
I tried it like this but it won't work:
create or replace PACKAGE BODY BEACHCOMBER IS
v_guest_count NUMBER;
BEGIN
SELECT COUNT (*) FROM A2_GUESTS
INTO v_guest_count;
END BEACHCOMBER;
Thank you
Edit: This is the 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;
You have A LOT of stuff wrong with your PL/SQL. I have modified the code below.
If you want to return a scalar result from a query, you either need an OUT parameter on the procedure, or create a function to return the value.
Syntax for "select into" is wrong.
You cannot access the value of a locally-scoped variable (v_guest_count) outside of the function/procedure.
create or replace FUNCTION BEACHCOMBER_COUNT
RETURN NUMBER
IS
v_guest_count NUMBER;
BEGIN
SELECT COUNT (*) INTO v_guest_count
FROM dual; -- A2_GUESTS;
RETURN v_guest_count;
END;
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_COUNT()));
END;
/
I would suggest getting a good pl/sql book.