Oracle PL/SQL: How to print a table type - oracle

I am trying to print an table type for debugging purposes, but don't know how. I tried the following two methods, neither of which work:
dbms_output.put_line (V_TEMP_TABTYPE(1));
dbms_output.put_line (V_TEMP_TABTYPE);
The error generated is: PLS-00306: wrong number or types of arguments in call to.
So, how can I print the contents of a table type? Or is there a different way to display the contents?
The table_type and the type it references are::
create or replace TYPE MY_TYPE IS OBJECT( MyString Varchar(20)
, counter Number(9) );
create or replace TYPE MY_TABTYPE AS TABLE OF MY_TYPE;

Oracle has objects but it's ... different. Not exactly sure with your question if you want to see the values of the properties or if you want to actually see the type.
CREATE OR REPLACE TYPE MY_TYPE IS OBJECT (
MyString Varchar(20)
, counter Number(9)
);
Now run some code for it.
DECLARE
myType MY_TYPE;
BEGIN
myType := MY_TYPE('ABC123',0);
-- To see the values reference the properties
DBMS_OUTPUT.PUT_LINE(myType.mystring);
-- To see they TYPE of the OBJECT
DBMS_OUTPUT.PUT_LINE(SYS.ANYDATA.CONVERTOBJECT(myType).getTypeName());
END;
Of course you can create methods on the object to return information for you a bit easier.
CREATE OR REPLACE TYPE MY_TYPE IS OBJECT (
MyString Varchar(20)
, counter Number(9)
, MEMBER FUNCTION getType RETURN VARCHAR2
, MEMBER FUNCTION toString RETURN VARCHAR2
)
/
CREATE OR REPLACE TYPE BODY MY_TYPE
AS
MEMBER FUNCTION getTYPE RETURN VARCHAR2 IS
BEGIN
RETURN SYS.ANYDATA.CONVERTOBJECT(SELF).getTypeName();
END;
MEMBER FUNCTION toString RETURN VARCHAR2 IS
BEGIN
RETURN 'MY_TYPE('||self.mystring||','||self.counter||')';
END;
END;
/
You can call the functions on the object now makes it easier to read imo.
DECLARE
mytype MY_TYPE;
BEGIN
mytype := MY_TYPE('AGAIN','0');
DBMS_OUTPUT.PUT_LINE(mytype.toString);
DBMS_OUTPUT.PUT_LINE(mytype.getType);
END;

dbms_output.put_line(v_temp_tabtype(i).myString);

Related

Setter methods in UDT in Oracle database

I'm still new to this and trying to get my head around it. UDT are able to define methods which you can call on the object stored, I seem to create a method that returns a value fine but was wondering if it's possible create a setter methods. This scenario isn't really useful but it's simple just for clarification
For example, I have this type:
create TYPE TestType2 AS OBJECT(
Numb NUMBER(4),
Str VARCHAR2(10),
MEMBER FUNCTION setNum(numba NUMBER) RETURN NUMBER
);
Which compiles fine so my assumption setter methods are allow
I've tried create the body type below:
CREATE TYPE BODY TestType2 as
member function setNum(numba NUMBER) return NUMBER is
begin
SELF.Numb := numba;
return SELF.Numb;
END;
END;
However this won't work giving me the errors below:
Error(3,9): PL/SQL: Statement ignored
Error(3,14): PLS-00363: expression 'SELF.NUMB' cannot be used as an assignment target
Is there a way to create a set method or is this only allowed in store procedures?
This is an obscure error. The problem is member functions take an implicit parameter of SELF. So if you want to change something you need to make the parameter explicit:
create or replace TYPE TestType2 AS OBJECT(
Numb NUMBER(4,0),
Str VARCHAR2(10),
MEMBER procedure setNum(self in out TestType2, numba NUMBER )
);
/
CREATE or replace TYPE BODY TestType2 as
member function setNum(self in out TestType2 , numba NUMBER) return NUMBER
is
begin
self.Numb := numba;
return SELF.Numb;
END;
END;
/
Note that the SELF parameter remains implicit when calling the function:
declare
t TestType2 := TestType2(4, 'TEST');
n pls_integer;
begin
dbms_output.put_line('1' || t.numb);
n := t.setNum(8);
dbms_output.put_line('2' || t.numb);
end;
/
Incidentally, setter methods don't need to be functions; we can have member procedures too.
create or replace TYPE TestType2 AS OBJECT(
Numb NUMBER(4,0),
Str VARCHAR2(10),
MEMBER procedure setNum(self in out TestType2, numba NUMBER ),
MEMBER FUNCTION getNum RETURN NUMBER
);
/
CREATE or replace TYPE BODY TestType2 as
member procedure setNum(self in out TestType2, numba NUMBER )
is
begin
self.Numb := numba;
END;
MEMBER FUNCTION getNum RETURN NUMBER
is
begin
return self.numb;
end;
END;
/

Oracle use defined type in package as record added to table of defined type

I have the following package.
CREATE OR REPLACE PACKAGE offer_actions AS
TYPE opis_oferty_type IS RECORD (nazwa varchar(11), rocznik number(4), cena decimal(10,2), imie_klienta varchar(32), nazwisko_klienta varchar(32));
TYPE opis_ofert_table IS TABLE OF varchar(100);
komis_id komisy.idk%TYPE :=0;
CURSOR c_oferty RETURN opis_oferty_type;
FUNCTION find_oferrs(komis_id number) RETURN opis_ofert_table;
END offer_actions;
/
CREATE OR REPLACE PACKAGE BODY offer_actions AS
CURSOR c_oferty RETURN opis_oferty_type IS
SELECT mar.nazwa, sze.rok_produkcji, ofe.cena_aktualna, kli.imie, kli.nazwisko FROM oferty ofe, szczegoly_oferty sze, modele modd, marki mar, klienci kli WHERE ofe.klient_id = kli.idk AND sze.oferta_id = ofe.idk AND ofe.model_id = modd.idk AND modd.marka_id = mar.idk AND ofe.komis_id = komis_id;
FUNCTION find_oferrs(komis_id number) RETURN opis_ofert_table IS
l_offers opis_ofert_table := opis_ofert_table();
BEGIN
FOR i in c_oferty LOOP
l_offers.EXTEND;
l_offers(l_offers.COUNT) := i.nazwa;
END LOOP;
RETURN l_offers;
END find_oferrs;
END offer_actions;
When I run script I get the following error.
PLS-00222: no function with name 'OPIS_OFERTY_TYPE' exists in this scope
How can I define opis_oferty_type to allow adding new record in operation
l_offers(l_offers.COUNT) := (opis_oferty_type(i.nazwa,i.rocznik,i.cena,i.imie_klienta, i.nazwisko_klienta));
Declared types.
CREATE OR REPLACE TYPE opis_oferty_type AS OBJECT
(nazwa varchar(11),
rocznik number(4),
cena decimal(10,2),
imie_klienta varchar(32),
nazwisko_klienta varchar(32)
);
/
CREATE OR REPLACE TYPE opis_ofert_table AS TABLE OF opis_oferty_type;
You are trying to use a record type like an object type. It's impossible.
Object types declared only at SQL level, record types only at PL/SQL level.
Either create type opis_oferty_type in SQL using create type ... as object, or continue to use a record type, but initialize every field of a record, like that:
Declare
l_v opis_oferty_type;
...
Begin
...
l_v.nazwa:= ...;
l_v.rocznik:= ...;
...
l_offers(l_offers.COUNT) := l_v;
Here's a pair of links for reference: Declaring Object Types, Initial Values of Record Variables

create a collection with 2 columns and insert all the rows at once PL/SQL

I have reference data which I want to use in a PL/SQL package.
This is a collection with two columns:
type table_info IS RECORD (
table_name VARCHAR2(50),
join_column VARCHAR2(50)
);
type config_tables_type is table of table_info; -- list of the config tables
I would like to add several rows at once to this collection, I tried this:
config_tables config_tables_type := config_tables_type (table_info('Commands','object_id'),
table_info('Contact_notificationcommands','command_object_id'),
table_info('Contactgroup_members','contact_object_id'),
table_info('Contactgroups','contact_object_id'),
table_info('Contactnotificationmethods','command_object_id'),
table_info('customvariables','object_id'),
table_info('Host_contactgroups','host_id'),
table_info('Host_contacts','host_id'),
table_info('Hostescalation_contactgroups','contactgroup_object_id'),
table_info('Hostescalation_contacts','contact_object_id'),
table_info('Host_parenthosts','parent_host_object_id'),
table_info('Hostdependencies','host_object_id'),
table_info('Hostdependencies','dependent_host_object_id'),
table_info('Hostescalations','host_object_id'),
table_info('Hostgroup_members','host_object_id'),
table_info('Hostgroups','hostgroup_object_id'),
table_info('Hosts','host_object_id'),
table_info('Service_contactgroups','contactgroup_object_id'),
table_info('Service_contacts','contact_object_id'),
table_info('Servicedependencies','service_object_id'),
table_info('Serviceescalation_contactgroups','contactgroup_object_id'),
table_info('Serviceescalation_contacts','contact_object_id'),
table_info('Serviceescalations','service_object_id'),
table_info('Servicegroup_members','service_object_id'),
table_info('Servicegroups','servicegroup_object_id'),
table_info('Services','service_object_id'),
table_info('Timeperiods','timeperiod_object_id')
);
But I have the following compilation error:
PLS-00222: no function with name 'TABLE_INFO' exists in this scope.
This type is declared in the package description and the initialisation of the config_tables collection is done in the package body.
Thanks
The below "hack" should do the trick!
declare
type table_info IS RECORD (
table_name VARCHAR2(50),
join_column VARCHAR2(50)
);
type config_tables_type is table of table_info;
config_tables config_tables_type;
function table_info_constructor(table_name VARCHAR2, join_column VARCHAR2) return table_info
is
t_i table_info;
begin
t_i.table_name := table_name;
t_i.join_column := join_column;
return(t_i);
end;
begin
config_tables := config_tables_type(table_info_constructor('Commands','object_id'),
table_info_constructor('Contact_notificationcommands','command_object_id'),
table_info_constructor('Contactgroup_members','contact_object_id'),
table_info_constructor('Contactgroups','contact_object_id'),
table_info_constructor('Contactnotificationmethods','command_object_id'),
table_info_constructor('customvariables','object_id'),
table_info_constructor('Host_contactgroups','host_id'),
table_info_constructor('Host_contacts','host_id'),
table_info_constructor('Hostescalation_contactgroups','contactgroup_object_id'),
table_info_constructor('Hostescalation_contacts','contact_object_id'),
table_info_constructor('Host_parenthosts','parent_host_object_id'),
table_info_constructor('Hostdependencies','host_object_id'),
table_info_constructor('Hostdependencies','dependent_host_object_id'),
table_info_constructor('Hostescalations','host_object_id'),
table_info_constructor('Hostgroup_members','host_object_id'),
table_info_constructor('Hostgroups','hostgroup_object_id'),
table_info_constructor('Hosts','host_object_id'),
table_info_constructor('Service_contactgroups','contactgroup_object_id'),
table_info_constructor('Service_contacts','contact_object_id'),
table_info_constructor('Servicedependencies','service_object_id'),
table_info_constructor('Serviceescalation_contactgroups','contactgroup_object_id'),
table_info_constructor('Serviceescalation_contacts','contact_object_id'),
table_info_constructor('Serviceescalations','service_object_id'),
table_info_constructor('Servicegroup_members','service_object_id'),
table_info_constructor('Servicegroups','servicegroup_object_id'),
table_info_constructor('Services','service_object_id'),
table_info_constructor('Timeperiods','timeperiod_object_id')
);
end;
Let me know how it works out for you.
For any further clarifications don't hesitate to ask me.
Ted.
There is an another alternative where you can basically create a schema level object i.e OBJECT type and TABLE Type and then call it in the plsql block as shown below. Hope this helps too.
--Create object type
CREATE OR REPLACE TYPE table_info
IS
OBJECT
(
table_name VARCHAR2(50),
join_column VARCHAR2(50))
/
--Create table type on Object type
CREATE OR REPLACE TYPE config_tables_type
IS
TABLE OF table_info
/
--PLSQL block of code
DECLARE
config_tables config_tables_type;
BEGIN
config_tables config_tables_type := config_tables_type (table_info('Commands','object_id'),
table_info('Contact_notificationcommands','command_object_id'),
table_info('Contactgroup_members','contact_object_id'),
table_info('Contactgroups','contact_object_id'),
table_info('Contactnotificationmethods','command_object_id'),
table_info('customvariables','object_id'),
table_info('Host_contactgroups','host_id'),
table_info('Host_contacts','host_id'),
table_info('Hostescalation_contactgroups','contactgroup_object_id'),
table_info('Hostescalation_contacts','contact_object_id'),
table_info('Host_parenthosts','parent_host_object_id'),
table_info('Hostdependencies','host_object_id'),
table_info('Hostdependencies','dependent_host_object_id'),
table_info('Hostescalations','host_object_id'),
table_info('Hostgroup_members','host_object_id'),
table_info('Hostgroups','hostgroup_object_id'),
table_info('Hosts','host_object_id'),
table_info('Service_contactgroups','contactgroup_object_id'),
table_info('Service_contacts','contact_object_id'),
table_info('Servicedependencies','service_object_id'),
table_info('Serviceescalation_contactgroups','contactgroup_object_id'),
table_info('Serviceescalation_contacts','contact_object_id'),
table_info('Serviceescalations','service_object_id'),
table_info('Servicegroup_members','service_object_id'),
table_info('Servicegroups','servicegroup_object_id'),
table_info('Services','service_object_id'),
table_info('Timeperiods','timeperiod_object_id')
);
END;
/

Passing values from Oracle Object type parameter to PLSQL Table type parameter

How can we pass a parameter that is declared as an Oracle Object type to a Procedure having a parameter as PLSQL Table type?
Eg:
Procedure A(p_obj_emp t_obj_emp)
Procedure B(p_emp_tab t_emp_tab)
Where t_obj_emp = Oracle Object and t_emp_tab is a PLSQL Table of binary_integer
How can we pass a parameter that is declared as an Oracle Object type to a Procedure having a parameter as PLSQL Record type?
Eg:
Procedure C(p_obj_dept t_obj_dept)
Procedure D(p_dept_rec t_dept_rec)
Where t_obj_dept = Oracle Object having 2 fields (deptid, deptname) and t_dept_rec is declared in package specification as t_dept_rec with 2 fields (deptid, deptname).
Kindly help with some example.
Thanks in advance
The following compiles for me and appears to do what you want:
CREATE OR REPLACE TYPE t_obj_emp AS OBJECT (
emp_id INTEGER,
emp_name VARCHAR2(100)
);
/
CREATE OR REPLACE TYPE t_obj_dept AS OBJECT (
dept_id INTEGER,
dept_name VARCHAR2(100)
);
/
CREATE OR REPLACE PACKAGE my_pkg AS
TYPE t_emp_tab IS TABLE OF t_obj_emp INDEX BY BINARY_INTEGER;
TYPE t_dept_rec IS RECORD (
dept_id INTEGER,
dept_name VARCHAR2(100)
);
PROCEDURE A(p_obj_emp t_obj_emp);
PROCEDURE B(p_emp_tab t_emp_tab);
PROCEDURE C(p_obj_dept t_obj_dept);
PROCEDURE D(p_dept_rec t_dept_rec);
END;
/
CREATE OR REPLACE PACKAGE BODY my_pkg AS
PROCEDURE A(p_obj_emp t_obj_emp)
IS
v_emp_tab t_emp_tab;
BEGIN
v_emp_tab(1) := p_obj_emp;
B(v_emp_tab);
END;
PROCEDURE B(p_emp_tab t_emp_tab) IS BEGIN NULL; END;
PROCEDURE C(p_obj_dept t_obj_dept)
IS
v_dept_rec t_dept_rec;
BEGIN
v_dept_rec.dept_id := p_obj_dept.dept_id;
v_dept_rec.dept_name := p_obj_dept.dept_name;
D(v_dept_rec);
END;
PROCEDURE D(p_dept_rec t_dept_rec) IS BEGIN NULL; END;
END;
/
Note that there isn't any 'convenient' way to create one object/record from another, even if they have identical members (such a t_obj_dept and t_dept_rec in the example above). You must copy across the values of all the fields individually.
You say that t_emp_tab is a "PLSQL Table of binary_integer". I'm guessing you mean that it's a PL/SQL Table of some type indexed by binary_integer, as it's far more common to index these tables by binary_integer than it is to store binary_integers in them. For the example above I've assumed that it's a table of t_obj_emps. If it's not, you'll have to map the t_obj_emp object to whatever type of object or record t_emp_tab is a table of.

Using %TYPE on a record field in PL/SQL

This has been driving me crazy for a while:
DECLARE
TYPE AttrValueRec IS RECORD (
attr VARCHAR2(40),
val VARCHAR2(2000),
inst NUMBER(4)
);
FUNCTION create_attrval(attr AttrValueRec.attr%TYPE,
val AttrValueRec.val%TYPE,
inst AttrValueRec.inst%TYPE := 1)
RETURN AttrValueRec IS
attr_value AttrValueRec;
BEGIN
attr_value.attr := attr;
attr_value.val := val;
attr_value.inst := inst;
RETURN attr_value;
END;
BEGIN
NULL;
END;
Using %TYPE on a record field does not seem to work. It produces the following error:
ORA-06550: line 8, column 36:
PLS-00206: %TYPE must be applied to a variable, column, field or attribute, not to "ATTRVALUEREC.ATTR"
ORA-06550: line 8, column 5:
PL/SQL: Item ignored
While explicitly defining the type again works:
DECLARE
TYPE AttrValueRec IS RECORD (
attr VARCHAR2(40),
val VARCHAR2(2000),
inst NUMBER(4)
);
FUNCTION create_attrval(attr VARCHAR2,
val VARCHAR2,
inst NUMBER := 1)
RETURN AttrValueRec IS
attr_value AttrValueRec;
BEGIN
attr_value.attr := attr;
attr_value.val := val;
attr_value.inst := inst;
RETURN attr_value;
END;
BEGIN
NULL;
END;
Can someone explain to me why it doesn't work? Is there a way to refer to the type declared in the record definition instead of explicitly defining it again in the function?
Thanks.
You need to actually create a variable of your type to refer to the attributes.
Add this after your type declaration and before the function.
attrib_value AttribValueRec;
Then in your function header you can reference the type of the attributes in your function like this:
attr attrib_value.attr%TYPE;
look at documentation. %TYPE and %ROWTYPE - only use to refer database columns. but you try to make referer to user type.
solution is define your pl/sql type with %TYPE-referer on a database column, and then create function with parameters that refer to the same database column.
UPDATE
its not full truth because lead commentator post usefull idea. summary %TYPE and %ROWTYPE can refer not only to table columns. refer ot "real" objects like variables and cursors are good too.

Resources