not able to delete an element from array - oracle

PLS-00306: wrong number or types of arguments in call to 'DELETE'
create or replace PACKAGE BODY MYPACKAGE AS
PROCEDURE LeaveDates4
(
I_STDATE IN DATE,
I_ENDDATE IN DATE,
O_DATES OUT DateArray
)
AS
n INTEGER := LEAST( I_ENDDATE - I_STDATE, 29 );
just_date DATE;
H_dates DateArray;
--cursor cur_holidates is select HOLIDAY_DATE from TSL_HOLIDAYLIST;
x number;
BEGIN
select count(*) into x from TSL_HOLIDAYLIST;
O_DATES := DateArray();
H_dates := DateArray();
O_DATES.EXTEND( n + 1 );
-- h_dates.extend;
dbms_output.put_line(n);
dbms_output.put_line(x);
FOR i IN 0 .. n LOOP
O_DATES(i+1) := I_STDATE + i;
dbms_output.put_line(I_STDATE + i);
END LOOP;
for cur in (select HOLIDAY_DATE from TSL_HOLIDAYLIST)
loop
h_dates.extend;
h_dates(h_dates.last):= cur.HOLIDAY_DATE;
end loop;
FOR i IN h_DATES.first..h_DATES.last LOOP
dbms_output.put_line(h_DATES(i)||i);
END LOOP;
for i in O_DATES.first..O_DATES.last LOOP
FOR j IN h_DATES.first..h_DATES.last LOOP
if o_dates(i)=h_dates(j)
then o_dates.delete(i); -- PLS-00306 error here
end if;
end loop;
end loop;
END LeaveDates4;
END MYPACKAGE;
The above code is failing with an error at o_dates.delete(i);
I want to delete the date from o_dates if it exists in h_dates.
The error I am getting is:
PLS-00306: wrong number or types of arguments in call to 'DELETE'

You can't delete elements from the middle of a varray.
PL/SQL Language Reference: PL/SQL Collections and Records: DELETE Collection Method
For a simpler example, define both a varray and a nested table collection:
create or replace type date_varray as varray(3) of date;
create or replace type date_ntab as table of date;
Now declare a collection of each type and try to deletion element from it.
Nested table:
declare
my_ntable date_ntab := date_ntab(sysdate -1, sysdate, sysdate +1);
begin
my_ntable.delete(2);
end;
PL/SQL procedure successfully completed.
Varray:
declare
my_varray date_varray := date_varray(sysdate -1, sysdate, sysdate +1);
begin
my_varray.delete(2);
end;
my_varray.delete(2);
*
ERROR at line 4:
ORA-06550: line 4, column 5:
PLS-00306: wrong number or types of arguments in call to 'DELETE'
ORA-06550: line 4, column 5:
PL/SQL: Statement ignored

Related

Show the output of a procedure in Oracle

The procedure uses the previous function to display the list of the products: num, designation and mention on the application.
SET SERVEROUTPUT ON;
CREATE OR REPLACE FUNCTION STORE(num_produit IN INTEGER) RETURN VARCHAR AS
N INTEGER := 0;
incre INTEGER := 0;
BEGIN
SELECT SUM(qte) INTO N FROM Ligne_Fact WHERE num_produit = produit;
IF N > 15 THEN
RETURN 'fort';
ELSIF N > 11 THEN
RETURN 'moyen';
END IF;
RETURN 'faible';
END;
/
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
BEGIN
SHOW_PRODUITS;
END;
/
I am sure that all the tables are filled with some dummy data, but I am getting the following error:
Function STOCKER compiled
Procedure AFFICHER_PRODUITS compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
4/4 PL/SQL: SQL Statement ignored
4/56 PL/SQL: ORA-00947: not enough values
Errors: check compiler log
Error starting at line : 28 in command -
BEGIN
AFFICHER_PRODUITS;
END;
Error report -
ORA-06550: line 2, column 5:
PLS-00905: object SYSTEM.SHOW_PRODUITS is invalid
ORA-06550: line 2, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
The first major mistake you've made is to create your objects in SYSTEM schema. It, just like SYS, are special and should be used only for system maintenance. Create your own user and do whatever you're doing there.
As of your question: select returns 3 values, but you're trying to put them into a single some_var variable. That won't work. Either add another local variables (for num and designation), or remove these columns from the select:
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
SELECT STORE(num) INTO SOME_VAR FROM Produit; --> here
dbms_output.enable();
dbms_output.put_line('result : '|| SOME_VAR);
END;
/
Code, as you put it, presumes that produit contains a single record (it can't be empty nor it can have 2 or more rows because you'll get various errors).
Maybe you wanted to access all rows; in that case, consider using a loop, e.g.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_VAR VARCHAR2(256);
BEGIN
FOR cur_r IN (SELECT num, designation, STORE(num) some_var FROM Produit) LOOP
dbms_output.put_line(cur_r.num ||', '|| cur_r.designation ||', result : '|| cur_r.some_var);
END LOOP;
END;
/
Then
set serveroutput on
BEGIN
SHOW_PRODUITS;
END;
/
You are trying to compile some stored routine which calls another stored routine named AFFICHER_PRODUITS and that routine calls SHOW_PRODUITS but SHOW_PRODUITS does not compile, hence the error. (By the way, it is recommended not to create your own stored routines in the SYSTEM schema.)
SHOW_PRODUITS does not compile because of this line:
SELECT num, designation, STORE(num) INTO SOME_VAR FROM Produit;
It appears that you want to get the query results as a string. In order to do that, you need to concatenate the column values, i.e.
SELECT num || designation || STORE(num) INTO SOME_VAR FROM Produit;
Of-course if all you want to do is display the query results, using DBMS_OUTPUT, you can declare a separate variable for each column.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
BEGIN
SELECT num
,designation
,STORE(num)
INTO SOME_NUM
,SOME_DES
,SOME_VAR
FROM Produit;
dbms_output.enable();
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END;
Note that if the query returns more than one row, you will [probably] need to use a cursor.
CREATE OR REPLACE PROCEDURE SHOW_PRODUITS IS
SOME_NUM Produit.num%type;
SOME_DES Produit.designation%type;
SOME_VAR VARCHAR2(6);
--
CURSOR c1 IS
SELECT num, designation, STORE(num) FROM Produit;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO SOME_NUM, SOME_DES, SOME_VAR;
EXIT WHEN c1%NOTFOUND;
dbms_output.put_line('result : ' || SOME_NUM || SOME_DES || SOME_VAR);
END LOOP;
CLOSE c1;
END;

PL/SQL Record populate

I have a record as following and I want to populate this with a for loop.
declare
type ch_type is table of record(id number, name varchar2(50));
type ch_type_tab is table of ch_type;
rec_typr ch_type_tab;
begin
for i in (select * from emp) loop
rec_typr.id := i.emp_id;
rec_typr.name := i.first_name;
end loop;
for i in rec_typr.first..rec_typr.last
loop
dbms_output.put_line(rec_typr(i).id);
end loop;
end;
but I get the error:
PLS:0302 component first must be declared.
Can you help me with this?
Two things are problematic in your code.
1) type ch_type is table of record is syntactically incorrect. You must first declare a record and then define its collection type.
2) Using implicit cursor loop is not an efficient method to load a collection and definitely can't be done the way you're trying to do. Use much simpler BULK COLLECT method instead.
declare
type ch_type is record(id number, name varchar2(50));
type ch_type_tab is table of ch_type;
rec_typr ch_type_tab;
begin
select emp_id,first_name bulk collect into
rec_typr from emp;
for i in rec_typr.first..rec_typr.last
loop
dbms_output.put_line(rec_typr(i).id);
end loop;
end;
/
Output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PL/SQL procedure successfully completed.
EDIT
I need to populate the record through a loop not through bulk collect.
Is it any way?
Yes, there is. But, it is less efficient than the method described above.
declare
type ch_type is record(id number, name varchar2(50));
type ch_type_tab is table of ch_type;
rec_typr ch_type_tab := ch_type_tab();
i INTEGER := 1;
begin
rec_typr.extend;
for rec in
(
select emp_id,first_name bulk collect into
rec_typr from emp
)
loop
rec_typr(i).id := rec.emp_id;
rec_typr(i).name := rec.first_name;
rec_typr.extend;
i := i + 1;
end loop;
for i in rec_typr.first..rec_typr.last
loop
dbms_output.put_line(rec_typr(i).id);
end loop;
end;
/

Wrong number or TYPES of arguments, error in PL/SQL

I have to create a list of RECORD and I need to send it to a procedure.
There is my header.
CREATE OR REPLACE PACKAGE tema4 IS
TYPE obj IS RECORD(id INTEGER := 0,percent INTEGER := 0);
TYPE listObj IS TABLE OF obj INDEX BY PLS_INTEGER;
PROCEDURE ex1 (p_listObj IN listObj);
END tema4;
My body.
create or replace PACKAGE BODY tema4 IS
PROCEDURE ex1 (p_listObj IN listObj) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Cant reach');
END ex1;
END tema4;
And my code that calls procedure ex1.
DECLARE
TYPE obj IS RECORD(id INTEGER := 0,percent INTEGER := 0);
TYPE listObj IS TABLE OF obj INDEX BY PLS_INTEGER;
v_obj obj;
v_listObj listObj;
BEGIN
FOR v_i IN (SELECT ID,BURSA FROM STUDENTI ORDER BY ID) LOOP
v_obj.id := v_i.id;
v_obj.percent := 50;
v_listObj(v_i.id) := v_obj;
END LOOP;
FOR v_i IN v_listObj.FIRST..v_listObj.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_listObj(v_i).id || ' - ' ||
v_listObj(v_i).percent);
END LOOP;
tema4.ex1(v_listObj); --this line is with problems
END;
PLS-00306: wrong number or types of arguments in call to 'EX1'
Can someone explain me what is wrong in my code? I also tried to create my type as global, but it won't let me because of 'RECORD' keyword.
Don't declare the types again (new types), use the types already declared in the package spec:
DECLARE
v_obj tema4.obj;
v_listObj tema4.listObj;
BEGIN
FOR v_i IN (SELECT ID,BURSA FROM STUDENTI ORDER BY ID) LOOP
v_obj.id := v_i.id;
v_obj.percent := 50;
v_listObj(v_i.id) := v_obj;
END LOOP;
FOR v_i IN v_listObj.FIRST..v_listObj.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_listObj(v_i).id || ' - ' ||
v_listObj(v_i).percent);
END LOOP;
tema4.ex1(v_listObj); --this line is with problems
END;

PLS-00201: identifier must be declared in Procedure

I have a PL/SQL Procedure code, which runs when it is / , but doesn't runs when it's executed. The error message I get is
SQL> EXECUTE MAXINUM;
BEGIN MAXINUM; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'MAXINUM' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
The code which I'm working on is :
DECLARE
N NUMBER;
M NUMBER;
O NUMBER;
P NUMBER;
X NUMBER;
PROCEDURE MAXINUM(N IN NUMBER, M IN NUMBER, O IN NUMBER, P IN NUMBER, X OUT NUMBER) IS
BEGIN
IF N>M AND N>O AND N>P THEN
X:=N;
ELSIF M>N AND M>O AND M>P THEN
X:=M;
ELSIF O>N AND O>M AND O>P THEN
X:=O;
ELSIF P>N AND P>M AND P>O THEN
X:=P;
END IF;
END;
BEGIN
N:=&NUMBER;
M:=&NUMBER;
O:=&NUMBER;
P:=&NUMBER;
MAXINUM(N,M,O,P,X);
DBMS_OUTPUT.PUT_LINE('HIGHEST NUMBER = '||X);
END;
/
When it gave the 'identifier error', I tried dropping this procedure I got the error:
SQL> DROP PROCEDURE MAXINUM;
DROP PROCEDURE MAXINUM
*
ERROR at line 1:
ORA-04043: object MAXINUM does not exist
I have so far read this, this, this solutions and other solutions some what related to this error.
You have written an anonymous block with a local procedure MAXINUM(). This procedure can be called within that block but does not exist outside that block. Consequently you cannot call it independently.
If you want to use the procedure elsewhere you need to create it as a first class database object:
create or replace procedure MAXINUM
(N IN NUMBER, M IN NUMBER, O IN NUMBER, P IN NUMBER, X OUT NUMBER)
is
BEGIN
IF N>M AND N>O AND N>P THEN
X:=N;
ELSIF M>N AND M>O AND M>P THEN
X:=M;
ELSIF O>N AND O>M AND O>P THEN
X:=O;
ELSIF P>N AND P>M AND P>O THEN
X:=P;
END IF;
END;
/
Now you can call it in your code, like this:
DECLARE
N NUMBER;
M NUMBER;
O NUMBER;
P NUMBER;
X NUMBER;
BEGIN
N:=&NUMBER;
M:=&NUMBER;
O:=&NUMBER;
P:=&NUMBER;
MAXINUM(N,M,O,P,X);
DBMS_OUTPUT.PUT_LINE('HIGHEST NUMBER = '||X);
END;
/
Points to note:
what happens if a parameter is null?
what happens if two arguments have the same value?
the convention would be to declare this as a function and return the highest value instead of setting an OUT parameter.
Incidentally I assume you're doing this as an exercise, as it is a re-implementation of an existing Oracle built-in function, greatest().

How to get the values of an OBJECT or ROWTYPE dynamically (Reflection) in Oracle PL/SQL?

I am trying to take a ROWTYPE, RECORD, or OBJECT type and dynamically convert it to a single string representation.
I want to do this dynamically.
Update: Doing this for an OBJECT type now working thanks to Justin Cave's feedback.
Example Data:
ID | VAL
---------
1 | BOB
Desired Output:
ID=1, VAL=BOB
Error Received:
ORA-06550: line 7, column 25:
PLS-00306: wrong number or types of arguments in call to 'TO_STRING'
ORA-06550: line 7, column 4:
PL/SQL: Statement ignored
What I have so Far (Doesn't loop through columns yet.):
CREATE OR REPLACE FUNCTION to_string (
ip_anydata in out anydata --note the "out" - this is required for the "piecewise"
)
RETURN VARCHAR2
IS
lv_typecode PLS_INTEGER;
lv_anytype anytype;
BEGIN
DBMS_OUTPUT.PUT_LINE('[Expected='||dbms_types.typecode_object||', Actual='||ip_anydata.getType(lv_anytype)||']');
--Get the typecode, and the ANYTYPE
lv_typecode := ip_anydata.getType(lv_anytype);
--Check that it's really an object
IF lv_typecode = dbms_types.typecode_object
THEN
--If it is an object, find the first item
DECLARE
lv_first_attribute_typecode pls_integer;
lv_aname varchar2(32767);
lv_result pls_integer;
lv_varchar varchar2(32767);
--Variables we don't really care about, but need for function output
lv_prec pls_integer;
lv_scale pls_integer;
lv_len pls_integer;
lv_csid pls_integer;
lv_csfrm pls_integer;
lv_attr_elt_type anytype;
BEGIN
lv_first_attribute_typecode := lv_anytype.getAttrElemInfo(
pos => 1, --First attribute
prec => lv_prec,
scale => lv_scale,
len => lv_len,
csid => lv_csid,
csfrm => lv_csfrm,
attr_elt_type => lv_attr_elt_type,
aname => lv_aname
);
--Check typecode of attribute
IF lv_first_attribute_typecode = dbms_types.typecode_varchar2
THEN
--Now that we've verified the type, get the actual value.
ip_anydata.piecewise;
lv_result := ip_anydata.getVarchar2(c => lv_varchar);
--DEBUG: Print the attribute name, in case you're curious
--dbms_output.put_line('lv_aname: '||lv_aname);
RETURN lv_aname||'='||lv_varchar;
ELSE
raise_application_error(-20000, 'Unexpected 1st Attribute Typecode: '||lv_first_attribute_typecode);
END IF;
END;
ELSE
raise_application_error(-20000, 'Unexpected Typecode: '||lv_typecode);
END IF;
END;
/
Scenario#1 - Select INTO w/ ROWTYPE:
DECLARE
lv_cv dual%ROWTYPE;
lv_str VARCHAR2(32767);
BEGIN
DBMS_OUTPUT.PUT_LINE('-----------------------------');
SELECT * INTO lv_cv FROM dual WHERE ROWNUM <= 1;
DBMS_OUTPUT.PUT_LINE(to_string(lv_cv));
END;
/
Scenario#2 - FETCH INTO w/ Cursor ROWTYPE:
DECLARE
CURSOR cv_cur IS SELECT * FROM dual WHERE ROWNUM <= 1;
lv_cv cv_cur%ROWTYPE;
lv_str VARCHAR2(32767);
BEGIN
DBMS_OUTPUT.PUT_LINE('-----------------------------');
OPEN cv_cur;
FETCH cv_cur INTO lv_cv;
CLOSE cv_cur;
DBMS_OUTPUT.PUT_LINE(to_string(lv_cv));
END;
/
Scenario#3 - Regular OBJECT: (Updated)
DECLARE
lv_cv T_CODE_VAL_REC := T_CODE_VAL_REC('BOB', 5);
lv_str VARCHAR2(32767);
lv_any ANYDATA;
BEGIN
DBMS_OUTPUT.PUT_LINE('-----------------------------');
lv_any := sys.anydata.ConvertObject(lv_cv);
DBMS_OUTPUT.PUT_LINE(to_string(lv_any));
EXCEPTION WHEN OTHERS THEN
pts2_test_valitation_util.fail(999, CHR(10)||CHR(10)||'Unexpected Error:'||CHR(10)||SQLERRM||CHR(10)||DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;
/

Resources