PLSQL : Using Member of with Nested Table of type NUMBER - PLS-00330: invalid use of type name or subtype name - oracle

Working with collections in plsql for the first time.
Declaraton of nested table :
TYPE nt_orders IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
nt_invc_orders nt_orders;
Where I am using member of
IF( 12345 member of nt_orders) THEN
nt_scb_temp_objects(i).invc_ref := p_invc_ref;
END IF;
NOTE : For now, I have entered 12345 as my search, in reality this will be a variable(of Number type) stored value.
ERROR : PLS-00330: invalid use of type name or subtype name

Your collection is actually not a nested table, it's an associative array. You should remove INDEX BY BINARY_INTEGER; to make it a nested table. Moreover, MEMBER OF function doesn't work with associative arrays. Second problem is you are searching for the element with the collection type - nt_orders as the right argument, which is wrong. It should be the nested table variable.
declare
TYPE nt_orders IS TABLE OF NUMBER;
nt_invc_orders nt_orders := nt_orders(12345);
begin
IF 12345 member of nt_invc_orders THEN
dbms_output.put_line('found');
else
dbms_output.put_line('not found');
END IF;
end;
/
Output
found
PL/SQL procedure successfully completed.

Related

is it possible to pass arrays as parameters in procedures?

i'm trying to pass an array as a parameter in my procedure but i keep getting a command unknown error
code
SET SERVEROUTPUT ON;
TYPE pourcentage_remise IS TABLE OF NUMBER INDEX BY commandeproduit.ref_produit%type;
CREATE OR REPLACE PROCEDURE remise_produit( pourcent IN pourcentage_remise,
ref_comm IN commande.ref_commande%type,
c_ht OUT commandeproduit.prix_ht%type,
c_ttc OUT commandeproduit.prix_ttc%type)
IS
CURSOR p_curs IS
SELECT ref_produit, prix_ttc, prix_ht FROM commandeproduit WHERE concerne = ref_comm ;
ref commandeproduit.ref_produit%type;
ttc commandeproduit.prix_ttc%type;
ht commandeproduit.prix_ht%type;
BEGIN
open p_curs;
LOOP
FETCH p_curs into ref, ttc, ht;
EXIT WHEN p_curs%notfound;
dbms_output.put_line(ref, ' ',ht, ' ', ttc);
IF pourcent(ref) THEN
ttc := ttc - ttc * pourcent(ref);
ht := ht - ttc * pourcent(ref);
INSERT INTO commandeproduit(prix_ht, prix_ttc) VALUES(ht, ttc) WHERE concerne = ref_comm AND ref_produit = ref;
END IF;
dbms_output.put_line(ref, ' ',ht, ' ', ttc);
END LOOP;
close p_curs;
END remise_produit;
/
procedure call
DECLARE
pourcentage pourcentage_remise;
reference commande.ref_commande%type :=1;
BEGIN
pourcentage('A01') :=0.15;
pourcentage('B15') :=0.2;
remise_produit(pourcentage, reference);
END;
/
the table
the error in french which means command unknown
please help
Your syntax error is on the declaration of your type so the rest of your code isn't really needed.
TYPE pourcentage_remise IS TABLE OF NUMBER INDEX BY commandeproduit.ref_produit%type;
Several problems
If you are trying to declare a type in SQL, you'd need to use a CREATE TYPE so you're missing the CREATE.
If you are trying to declare a table type in SQL, you can't use an associative array. You'd realistically want a nested table instead.
If you are trying to declare a PL/SQL type, your statement would need to be in a PL/SQL block. You could declare a package that contains an associative array type.
If you want to declare a nested table type in SQL
CREATE TYPE pourcentage_remise IS TABLE OF NUMBER;
If you want to declare an associative array in a PL/SQL package
CREATE OR REPLACE PACKAGE my_collection_pkg
AS
TYPE pourcentage_remise IS TABLE OF NUMBER INDEX BY commandeproduit.ref_produit%type;
END;
If you want to use a nested table type, that changes how you need to initialize your associative array. It should change how you reference elements of that array, but I'm confused by your code. Your procedure appears to be using a numeric index to access an element of the associative array which doesn't make sense if the associative array uses a string as the index.

Oracle - TYPE TABLE - Collection Method EXISTS in IF Statement - ORA-06502: PL/SQL: erro: character to number conversion error

I need to make a collection in a Package, but I don't know where was the mistake...
This is my declaration and initialization:
avversao varchar2(30);
TYPE tListaVersaoHomologada IS TABLE OF NVARCHAR2(30);
vVersaoHomologada tListaVersaoHomologada := tListaVersaoHomologada('0.06', '0.07');
And this is where raise the exception
if NOT(vVersaoHomologada.EXISTS(avversao)) then
...
end if;
The variable
avversao
Have one of the values:
0.06
0.07
Reference:
Using PL/SQL Collections and Records
Collection Methods
member of - checking if value exists in collection.
EXISTS - Is for check if collection has value in index.
declare
avversao varchar2(30) := '0.06';
TYPE tListaVersaoHomologada IS TABLE OF VARCHAR2(30);
vVersaoHomologada tListaVersaoHomologada := tListaVersaoHomologada('0.06', '0.07');
begin
if avversao member of vVersaoHomologada then
dbms_output.put_line('!!!!Exist!!!!!');
end if;
end;

'ORA-00913: too many values' while reading data from xml to user-defined record (PL/SQL)

I get this error while executing the follwing PL/SQL code and I can't figure out why.
PLS-00382: expression is of wrong type
PL/SQL: ORA-00913: too many values
PL/SQL: SQL Statement ignored
I understand that the cause of ORA-00913 is a mismatch of values in the two sets of data being referred to in the SELECT statement.
The code was working fine before I added the checkVar variable in the record. Just wanted to know if there is any way to fix this without taking out the checkVar from testRec record?
DECLARE
X XMLType:=XMLType( '<Testmain>
<TeamSel>
<code>abc123</code>
<name>awrqer</name>
</TeamSel>
<TeamSel>
<code>abc678</code>
<name>gokhg</name>
</TeamSel>
</Testmain>
');
TYPE testRec IS RECORD(
name VARCHAR2(512),
code VARCHAR2(512),
checkVar BOOLEAN:=FALSE
);
TYPE testRecTab IS TABLE OF testRec INDEX BY BINARY_INTEGER;
testList testRecTab;
BEGIN
SELECT EXTRACTVALUE(VALUE(xml_list),'//Name') AS lname,
EXTRACTVALUE(VALUE(xml_list),'//Code') AS lcode
BULK COLLECT
INTO testList
FROM TABLE(XMLSEQUENCE(EXTRACT(X,'Testmain/TeamSel'))) xml_list;
--rest of the code
END;
You can't select into a Boolean variable so I think there are two options:
a) Remove the boolean from your record type
b) Populate your table in a loop like the example below
DECLARE
X XMLType:=XMLType( '<Testmain>
<TeamSel>
<code>abc123</code>
<name>awrqer</name>
</TeamSel>
<TeamSel>
<code>abc678</code>
<name>gokhg</name>
</TeamSel>
</Testmain>
');
TYPE testRec IS RECORD(
name VARCHAR2(512),
code VARCHAR2(512),
checkVar BOOLEAN:=FALSE
);
TYPE testRecTab IS TABLE OF testRec INDEX BY BINARY_INTEGER;
lTestRec testRec;
testList testRecTab;
BEGIN
FOR cRecord IN (
SELECT EXTRACTVALUE(VALUE(xml_list),'//name') lname,
EXTRACTVALUE(VALUE(xml_list),'//code') lcode
FROM TABLE(XMLSEQUENCE(EXTRACT(X,'Testmain/TeamSel'))) xml_list
)
LOOP
lTestRec.name := cRecord.lname;
lTestRec.code := cRecord.lcode;
testList(testList.count + 1) := lTestRec;
END LOOP;
--rest of the code
END;

Oracle table function on multi-layer-collection

I have a need for two Collection types in my program. I've made a simplified example.
type Trec1 is record (Tval1 number);
type Ttab1 is table of Trec1;
type Trec2 is record
(
Tval1 number,
Tval2 Ttab1
);
type Ttab2 is table of Trec2;
This Query Works fine:
select Max (Tval1) from table (Ttab1);
Whereas
select Max (Tval1) from table (Ttab2);
gives me
[Error] PLS-00382 (40: 44): PLS-00382: expression is of wrong type
[Error] ORA-22905 (40: 37): PL/SQL: ORA-22905: cannot access rows from a non-nested table item
I've concluded that the Collection with a nested Collection is what causes the errors. Is there any way to do table functions on this type of Collection, or should i loop through it normally?
To be this works perfectly.
But I have created it as SQL types, not a PL/SQL type.
Added sample code for the same
Case 1:
create type SUBTYP1 as OBJECT
(
AGE NUMBER,
NAME VARCHAR2(10)
);
/
create type TABLETYP1 AS TABLE OF SUBTYP1;
/
DECLARE
ty1 TABLETYP1 := TABLETYP1() ;
v_age number;
v_name varchar2(10);
BEGIn
ty1.extend;
ty1(1) := SUBTYP1(12,'Mahesh');
SELECT * into v_age,v_name from TABLE(ty1);
dbms_output.put_line(v_age||':'||v_name);
END;
/
Case 2:
create or replace type SUBTYP2 as OBJECT
(
AGE NUMBER,
typ1 TABLETYP1
);
/
create type TABLETYP2 AS TABLE OF SUBTYP2;
/
DECLARE
ty2 TABLETYP2 := TABLETYP2() ;
ty1 TABLETYP1 := TABLETYP1() ;
v_age number;
v_name varchar2(10);
BEGIn
ty1.extend;
ty1(1) := SUBTYP1(12,'Mahesh');
ty2.extend;
ty2(1) := SUBTYP2(14,ty1);
SELECT AGE into v_age from TABLE(ty2);
dbms_output.put_line(v_age);
END;
/
What you described are PL/SQL types and they work only in PL/SQL not in SQL. So I doubt that
select Max (Tval1) from table (Ttab1);
works fine. Can you show full creation script and output please?
If you need to have complex types returned by your query you need to create SQL collection (aka nested table) and SQL Object Type (instead of record). They are created with individual CREATE statement and they are persistent objects stored in data dictionary.

Find specific varchar in Oracle Nested Table

I'm new to PL-SQL, and struggling to find clear documentation of operations are nested tables. Please correct any misused terminology etc.
I have a nested table type that I use as a parameters for a stored procedure.
CREATE OR REPLACE TYPE "STRARRAY" AS TABLE OF VARCHAR2 (255)
In my stored procedure, the table is initialized and populated. Say I have a VARCHAR2 variable, and I want to know true or false if that varchar exists in the nested table.
I tried
strarray.exists('somevarchar')
but I get an ORA-6502
Is there an easier way to do that other than iterating?
FOR i IN strarray.FIRST..strarray.LAST
LOOP
IF strarray(i) = value THEN
return 1;--found
END IF;
END LOOP;
For single value check I prefer the "member" operator.
zep#dev> declare
2 enames strarray;
3 wordToFind varchar2(255) := 'King';
4 begin
5 select emp.last_name bulk collect
6 into enames
7 from employees emp;
8 if wordToFind member of enames then
9 dbms_output.put_line('Found King');
10 end if;
11 end;
12 /
Found King
PL/SQL procedure successfully completed
zep#dev>
You can use the MULTISET INTERSECT operator to determine whether the string you're interested in exists in the collection. For example
declare
l_enames strarray;
l_interesting_enames strarray := new strarray( 'KING' );
begin
select ename
bulk collect into l_enames
from emp;
if( l_interesting_enames = l_interesting_enames MULTISET INTERSECT l_enames )
then
dbms_output.put_line( 'Found King' );
end if;
end;
will print out "Found King" if the string "KING" is an element of the l_enames collection.
You should pass an array index, not an array value to an exists in case you'd like to determine whether this element exists in collection. Nested tables are indexed by integers, so there's no way to reference them by strings.
However, you might want to look at associative arrays instead of collections in case you wish to reference your array element by string index. This will look like this:
DECLARE
TYPE assocArray IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
myArray assocArray;
BEGIN
myArray('foo') := 'bar';
IF myArray.exists('baz') THEN
dbms_output.put_line(myArray('baz'));
ELSIF myArray.exists('foo') THEN
dbms_output.put_line(myArray('foo'));
END IF;
END;
Basically, if your array values are distinct, you can create paired arrays referencing each other, like,
arr('b') := 'a'; arr('a') := 'b';
This technique might help you to easily look up any element and its index.
When a nested table is declared as a schema-level type, as you have done, it can be used in any SQL query as a table. So you can write a simple function like so:
CREATE OR REPLACE FUNCTION exists_in( str VARCHAR2, tab stararray)
RETURN BOOLEAN
AS
c INTEGER;
BEGIN
SELECT COUNT(*)
INTO c
FROM TABLE(CAST(tab AS strarray))
WHERE column_value = str;
RETURN (c > 0);
END exists_in;

Resources