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.
Related
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.
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.
Is it possible to create an Algebraic Data Type in Postgres and then use it as a column type?
For example:
CREATE TYPE hoofed AS ENUM('horse', 'goat');
CREATE TYPE monkey AS ENUM('chimp','macaque');
CREATE TYPE ANIMAL AS ENUM(hoofed, monkey);
This fails with:
syntax error at or near "hoofed"
LINE 1: CREATE TYPE ANIMAL AS ENUM(hoofed, monkey);
Is it possible to do something like this?
Ultimately what I would then like to be able to do is something like so:
CREATE TABLE zoo (
a ANIMAL,
name text
);
INSERT INTO zoo(a, name) VALUES('horse', 'bob');
INSERT INTO zoo(a, name) VALUES('macaque', 'jimmy');
And for both of the records to be independently valid.
EDIT: #Abihabi87's response below does allow me to create, in effect, a product type, but it still does not allow me to create a union type as desired.
You cant create type enum from others enum type:
you can create ANIMAL that like:
CREATE TYPE ANIMAL AS (h hoofed,m monkey);
Example in use:
CREATE TABLE your_table
(
a ANIMAL
);
INSERT INTO your_table(a) select (select ('horse','macaque')::ANIMAL);
With ENUM types, you cannot achieve dynamic type composition/union. However, with DOMAIN types, you could achieve something similar:
create function valid_any_domain(anyelement, variadic regtype[])
returns boolean
language plpgsql
immutable
as $func$
declare
t regtype;
begin
foreach t in array $2 loop
begin
execute format('select $1::%s', t) using $1;
exception
when not_null_violation or check_violation then
continue;
end;
return true;
end loop;
return false;
end;
$func$;
create domain hoofed as text
check (value in ('horse', 'goat'));
create domain monkey as text
check (value in ('chimp','macaque'));
create domain animal as text
check (valid_any_domain(value, 'hoofed', 'monkey'));
Changing the base types will dynamically change the composite/union type too, but still requires a manual constraint validation (especially, when some value(s) are removed from the valid spectrum):
alter domain hoofed drop constraint hoofed_check;
alter domain hoofed add check (value in ('horse', 'goat', 'zebra'));
alter domain animal validate constraint animal_check;
http://rextester.com/MBVC62095
Note: however, with DOMAIN types, you will lose an ENUM property: the custom ordering. DOMAINs will always use the underlying type's ordering.
Use the function:
create or replace function create_enum(name, variadic regtype[])
returns void language plpgsql as $$
begin
execute format(
'create type %I as enum(%s)',
$1,
string_agg(quote_literal(enumlabel), ',' order by enumtypid, enumsortorder))
from pg_enum
where enumtypid = any($2);
end $$;
Pass the name of a new type and a list of enum types as arguments:
select create_enum('animal', 'hoofed', 'monkey');
select enum_range(null::animal) as animal;
animal
----------------------------
{horse,goat,chimp,macaque}
(1 row)
Effectively you are trying to merge two enum types.
There are some open questions:
Can there be duplicate strings?
Is the design supposed to be static (changes to enum type hoofed do not change type animal later) or dynamic (the opposite).
Merge exactly two enum types or more?
Since the order of elements is significant, what is the order of elements in animal supposed to be?
Is this a one-time operation or intended for repeated use?
Assuming no duplicates, static design, two enum types, existing order of elements as appended and one-time operation.
You can use the built-in enum support function enum_range(anyenum) to get an array of all elements for a given enum type.
DO
$$
BEGIN
EXECUTE (
SELECT 'CREATE TYPE animal AS ENUM ('
|| array_to_string(enum_range(null::hoofed)::text[]
|| enum_range(null::monkey)::text[], ''',''')
|| ''')'
);
END
$$;
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.
I have a problem with SQL Object (ORACLE). :(
I have an abstract type Forum, generalized in ForumCategory, and a type Category :
CREATE OR REPLACE TYPE Forum_t AS OBJECT
(
moderators Users_table_ref,
topics Topics_table,
MEMBER FUNCTION getName RETURN VARCHAR2
)
NOT FINAL NOT INSTANTIABLE;
/
CREATE TABLE Forum OF Forum_t
NESTED TABLE moderators STORE AS Liste_moderators,
NESTED TABLE topics STORE AS Liste_topics
(NESTED TABLE posts STORE AS Liste_posts);
CREATE OR REPLACE TYPE ForumCategory_t UNDER Forum_t
(
category REF Category_t,
OVERRIDING MEMBER FUNCTION getName RETURN VARCHAR2
);
/
CREATE OR REPLACE TYPE BODY ForumCategory_t AS
OVERRIDING MEMBER FUNCTION getName RETURN VARCHAR2 IS
c Category_t;
BEGIN
SELECT DEREF(SELF.category) INTO c FROM DUAL;
RETURN c.name;
END getName;
END;
/
CREATE OR REPLACE TYPE Category_t AS OBJECT
(
name VARCHAR2(60)
);
/
CREATE TABLE Category OF Category_t
(
CONSTRAINT PK_CAT_NAME PRIMARY KEY(name)
);
I want to make a trigger after insert on table Category which insert a ForumCategory_t on table Forum.
I have this code :
CREATE OR REPLACE TRIGGER Category_insert
AFTER INSERT ON Category
FOR EACH ROW
DECLARE
ref_cat REF Category_t;
BEGIN
SELECT REF(c) INTO ref_cat
FROM Category c
WHERE c.name = :NEW.name;
INSERT INTO Forum VALUES(ForumCategory_t(Users_table_ref(),Topics_table(),ref_cat));
END;
/
The beginning don't work, I cannot select REF of the inserted Category (it's work outside the trigger).
Please, I need help ^^
PS : Sorry for my english