I need to select the REF(SELF) in a method of an object. For example:
CREATE TYPE SOMETYPE_TY AS OBJECT(
attr1 VARCHAR2(20),
attr2 DATE,
MEMBER PROCEDURE AddSomething(A1 VARCHAR2, A2 VARCHAR2)
) NOT FINAL;
How can I get the REF(SELF) in a method, like the following?
CREATE OR REPLACE TYPE BODY SOMETYPE_TY AS
MEMBER PROCEDURE AddSomething(A1 VARCHAR2, A2 VARCHAR2) AS
some_ref REF SOMETYPE_TY;
BEGIN
SELECT REF(SELF) INTO some_ref FROM DUAL;
END AddSomething;
END;
/
I tried with the DUAL table but it tells me ORA-24344: success with compilation error
You cannot. A REF is a pointer to a row in an object-derived table; it is not a pointer to an object.
From the REF documentation:
REF takes as its argument a correlation variable (table alias) associated with a row of an object table or an object view. A REF value is returned for the object instance that is bound to the variable or row.
To be able to get a REFerence to an object you need to put that object into a table and then get the REFerence to the table row.
Related
I am new in PL/SQL and having problem with PL/SQL
I want to write object method which has parameter shop name (in the table) and returns total amount of goods in shop.
Let`s say name of shop could be "Center".
CREATE TYPE SHOPS_TYP AS OBJECT (
S_NUM NUMBER,
S_NAME VARCHAR2(30),
TEL VARCHAR2(20)
);
/
CREATE TYPE GOODS_T AS OBJECT(
G_NUM NUMBER,
G_NAME VARCHAR2(30),
G_QUANTITY NUMBER,
G_PRICE NUMBER,
NUM_SHOP REF SHOPS_TYP,
ORDER MEMBER FUNCTION total(x GOODS_T) RETURN INTEGER
);
/
CREATE TABLE GOODS OF GOODS_TYP;
CREATE TYPE BODY GOODS_TYP AS
ORDER MEMBER FUNCTION total(x GOODS_TYP) RETURN INTEGER IS
BEGIN
RETURN (SELECT SUM(G.G_NUM) FROM GOODS G WHERE G.NUM_SHOP.S_NAME = x);
END;
END;
SELECT Value(A) from GOODS A where A.total('centers');
When I run the code above I am getting error in "RETURN" part of method. How can I implement this query ?
Return has to return an expression. The documentation defines expression as:
"an arbitrarily complex combination of operands (variables, constants, literals, operators, function invocations, and placeholders) and operators"
This does not include a result set, so change your method to look like this:
ORDER MEMBER FUNCTION total(x GOODS_TYP) RETURN INTEGER IS
return_value number;
BEGIN
SELECT SUM(G.G_NUM)
into return_value
FROM GOODS G WHERE G.NUM_SHOP.S_NAME = x;
RETURN return_value;
END;
By the way, you should make life easier for yourself and your colleagues by using one naming convention for your objects.
I am trying to create the following datatype with 2 functions:
-- Employee
CREATE OR REPLACE TYPE EmployeeType AS OBJECT (
EmployeeNumber NUMBER,
EmployeeName VARCHAR2(150),
EmployeeAddress VARCHAR2(255),
MAP MEMBER FUNCTION getEmployeeNumber RETURN NUMBER,
MEMBER FUNCTION CalculateSalary RETURN FLOAT(2)
)
NOT FINAL;
CREATE OR REPLACE TYPE BODY EmployeeType AS
MAP MEMBER FUNCTION getEmployeeNumber RETURN NUMBER IS
BEGIN
RETURN EmployeeNumber;
END;
-- function that can be overriden by subtypes, make abstract
MEMBER FUNCTION CalculateSalary RETURN FLOAT(2) IS
BEGIN
-- function returns empty, has to be overwritten by fulltimeemployee
RETURN 0.00;
END;
END;
However I keep getting an error stating
ERROR: ORA-00900: invalid SQL statement
Error Code: 900
Query = END
I am using RazorSQL to execute my queries, I cant seem to get the line number causing this error but through trial and error I have found it to be one of the function descriptions in my TYPE BODY definition.
I have tried adding / after the last END; but it does not help solve the issue.
Replace FLOAT(2) with just FLOAT:
CREATE OR REPLACE TYPE EmployeeType AS OBJECT (
EmployeeNumber NUMBER,
EmployeeName VARCHAR2(150),
EmployeeAddress VARCHAR2(255),
MAP MEMBER FUNCTION getEmployeeNumber RETURN NUMBER,
MEMBER FUNCTION CalculateSalary RETURN FLOAT
)
NOT FINAL;
/
CREATE OR REPLACE TYPE BODY EmployeeType AS
MAP MEMBER FUNCTION getEmployeeNumber RETURN NUMBER IS
BEGIN
RETURN EmployeeNumber;
END;
-- function that can be overriden by subtypes, make abstract
MEMBER FUNCTION CalculateSalary RETURN FLOAT IS
BEGIN
-- function returns empty, has to be overwritten by fulltimeemployee
RETURN 0.00;
END;
END;
/
The documentation for CREATE TYPE doesn't mention this, but you can find the explanation in the topic related to CREATE FUNCTION : http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/create_function.htm
RETURN datatype
RETURN datatype For datatype, specify the data type of the return value of the function. The return value can have any data type
supported by PL/SQL.
............ The data type cannot specify a length, precision, or scale.
The database derives the length, precision, or scale of the return value
from the environment from which the function is called.
Hey there I have a function, and part of the function is to make sure that the selected value is within the passed in table of varchar2s. To start I declare a varchar2 table type like so.
create or replace type Varchar2Table is table of varchar2(200)
Then I have the function which accepts the nested table parameter and has a select statement on them.
function SelectPeople(inputNames Varchar2Table) return People
begin
--stuff
select * from person_table where name in inputNames; --line of interest
--more stuff
end;
This doesn't seem to work though, I get the following error:
ORA-00932: inconsistent datatypes: expected NUMBER got
ENGSPL5.VARCHAR2TABLE
Any suggestions?
The TABLE operator allows nested tables to be used in SQL statements. The function was also missing an IS and an INTO.
create or replace type Varchar2Table is table of varchar2(200);
create table person_table(id number, name varchar2(100));
create or replace function SelectPeople(inputNames Varchar2Table) return number
is --Missing "IS".
type numberTable is table of number; --Need a collection to store results.
numbers numberTable;
begin
select id
bulk collect into numbers --Missing "INTO".
from person_table
where name in (select column_value from table(inputNames)); --Missing "TABLE".
--Alternatively a multiset condition can be used.
--where name member of inputNames;
--Dummy return value to make the function compile.
return 1;
end;
/
In SQL, how can I create a simple method to retrieve a value from an object?
Here is the code:
create type CurrentUser_objtyp as Object (
CurrUserName varchar2(20),
CurrUserPassword varchar2(20),
CurrUserType varchar2(15)
)
/
How can I retrieve the value of CurrUserName from a method?
As Oracle SQL types only allow public attributes there is no point in creating getter and setter methods for them.
But the general principle is to create member methods:
create type CurrentUser_objtyp as Object (
CurrUserName varchar2(20),
CurrUserPassword varchar2(20),
CurrUserType varchar2(15),
member function getname return varchar2
)
/
You need to write a body for the implementation, which is basically PL/SQL:
create type body CurrentUser_objtyp as
member function getname return varchar2
is
begin
return self.CurrUserName;
end;
end;
/
"How do I call the member function in your above code?"
To call a member function (or procedure) we first have to instantiate the object. There are various different ways of using objects, but again here is the simplest:
declare
currUser CurrentUser_objtyp := new CurrentUser_objtyp('MR KNOX', 'PASSWORD1', 'MANAGER');
begin
dbms_output.put_line('user name is '||currUser.getname);
end;
/
Oracle have devoted an entire manual to their Object-Relational constructs. You should read it to find out more.
I'm new in PLSQL (about a week) and I have an object with hundreds attributes and I need to check which ones are filled and null to add to a clob.
It is possible to iterate in the object attributes like
for i in object loop
object.i
end loop;
Using standard PL/SQL construct you cannot. You can iterate through a collection using
for i in mycol.FIRST .. mycol.LAST loop
Variable i is not index but one element of the iterated collection.
If your object is an Oracle TYPE you can query a system view ALL_TYPE_ATTRS. This view is part of a database catalog. You find its description in Oracle Reference (not Oracle SQL Reference!). You get a list of attribute names, I'm not sure, if you can access it in dynamic way.
The simplest way is to write a set of helper procedures which will check an attribute according its type and manage its value and then simply call this procedure.
declare
procedure Manage_Char_Attr(value IN VARCHAR2, pclob CLOB) IS
BEGIN
if value is null then
...
END;
procedure Manage_Number_Attr(value IN NUMBER, pclob CLOB) IS
...
procedure Manage_Date_Attr(value IN DATE, pclob CLOB) IS
...
CLOB myclob
begin
-- initialize your CLOB
...
-- manage attributes
Manage_Char_Attr(attr1, myclob); -- let attr1 is a string
Manage_Char_Attr(attr2, myclob); -- let attr2 is a string
Manage_Numvber_Attr(attr3, myclob); -- let attr3 is a number
Manage_Date_Attr(attr4, myclob); -- let attr4 is a date
...
end;