SuperType Table of subtype objects not showing added attributes - sql

I am trying to make a supertype table of objects that holds subtype objects, but the bottom line insert once ran shows the first two attributes SSN and name as inserted. Is Oracle Express just broken these days? or is there something wrong in my code?
create or replace type PersonType as object (
SSN number (9),
name varchar2(30))
Instantiable
NOT Final;
create or replace type TenantType under PersonType (
aptNum REF ApartmentType,
phone number(10),
car varchar2(15),
contract varchar2(10));
Instantiable
Final;
create or replace type EmployeeType under PersonType (
empId number(4),
empAdr varchar2(40));
Instantiable
Final;
create table P1 of PersonType (
constraint P1_SSN_pk Primary Key (SSN));
insert into P1 values(TenantType(956785252, 'Jerry Wilson', (select ref(a) from A1 a where aptNum = 110), 8015167895, 'Toyota', '8 months'));

If you run simple select you see common values of supertype. When creating types you can add member function to display subtypes in different ways or you can use treat():
select treat(value(p) as tenanttype) from p1 p where p.ssn = 956785252
You have typos (unnecessary semicolons in type definitions) and missing definition of ApartmentType and table a1, so here are my test data: dbfiddle
And here are examples of mentioned member function show(): Inheritance in SQL Object Types

Related

How to overcome a persistent oracle 'invalid identifier' error on a basic insert?

I am trying to create a basic table using subtypes and insert some data into this in Oracle Express 11g.
My table is successfully created but i am having issues with inserting data.
The result of my insert statement always throws back an error 'SQL Error: ORA-00904: "BRANCH_PHONE": invalid identifier'.
The column which shows up in the error message is always the column which is at the end of the insert statement, despite the column existing in the table. I have tried the following code:
create type addressType as object(
street varchar2(20),
city varchar2(20),
postCode varchar2(8))
not final
/
create type branchType as object(
branchID int,
branch_address addressType,
branch_phone int(11))
not final
/
create table Branch of branchType(
constraint branch_pk primary key(branchID));
/
insert into Branch values (
branchID('2364'),
addressType('12 Rooster','Atlantis','A13 4UG'),
branch_phone('01316521311'));
I would really appreciate any ideas.
I made some changes, including changing the branch_phone to varchar2. A Phone number, while is "numbers" is not a data type of number. it is a string of characters. Also you were passing branchID as a string, but you are declaring it as a number, so changed that also. BranchID and branch_phone are primitive data types, so no constructor needed.
create type addressType as object(
street varchar2(20),
city varchar2(20),
postCode varchar2(8))
not final
/
create type branchType as object(
branchID int,
branch_address addressType,
branch_phone varchar2(11))
not final
/
create table Branch of branchType(
constraint branch_pk primary key(branchID));
/
insert into Branch values (
branchtype(2364,
addressType('12 Rooster','Atlantis','A13 4UG'),
'01316521311') )

Oracle OR - how to guarantee that a nested table has references to all the subtypes of a supertype

I'm designing an object-relational model database. I have a supertype named "topico_t" and 4 subtypes of this supertype named "anotacao_t", "tarefa_t", "memo_t" and "contacto_t". See here the DDL snippet:
CREATE OR REPLACE TYPE categoria_t AS OBJECT(
nome VARCHAR2(25),
pai REF categoria_t
);
CREATE OR REPLACE TYPE categoria_tab_t AS TABLE OF REF categoria_t;
CREATE OR REPLACE TYPE topico_t AS OBJECT(
titulo VARCHAR2(100),
ultimaAlteracao DATE,
categorias categoria_tab_t
--referencias topico_tab_t
) NOT FINAL;
CREATE OR REPLACE TYPE topico_tab_t AS TABLE OF REF topico_t;
ALTER TYPE topico_t ADD ATTRIBUTE referencias topico_tab_t CASCADE;
CREATE OR REPLACE TYPE periodo_t AS OBJECT(
inicio DATE,
fim DATE
);
CREATE OR REPLACE TYPE repeticao_t AS OBJECT(
frequencia VARCHAR2(10),
duracao periodo_t
);
CREATE OR REPLACE TYPE anotacao_t UNDER topico_t(
periodo periodo_t,
repeticao repeticao_t
);
CREATE OR REPLACE TYPE telefone_t AS OBJECT(
numero VARCHAR2(25)
);
CREATE OR REPLACE TYPE telefone_tab_t AS TABLE OF telefone_t;
CREATE OR REPLACE TYPE morada_t AS OBJECT(
rua VARCHAR2(100),
localidade VARCHAR2(50),
codigoPostal VARCHAR2(10)
);
CREATE OR REPLACE TYPE morada_tab_t AS TABLE OF morada_t;
CREATE OR REPLACE TYPE contacto_t UNDER topico_t(
telefones telefone_tab_t,
moradas morada_tab_t,
email VARCHAR2(100),
url VARCHAR2(150)
);
CREATE OR REPLACE TYPE tarefa_t UNDER topico_t(
dataFim DATE,
completo NUMBER(1,0),
conteudo VARCHAR2(255)
);
CREATE OR REPLACE TYPE memo_t UNDER topico_t(
conteudo VARCHAR2(255)
);
CREATE TABLE categorias OF categoria_t;
CREATE TABLE topicos OF topico_t
NESTED TABLE categorias STORE AS categorias_nested
NESTED TABLE referencias STORE AS referencias_nested;
So, then I populate this table "topicos" with this:
INSERT INTO topicos VALUES (tarefa_t(
'Dissertacao',
TO_DATE('2018/02/13', 'YYYY/MM/DD'),
categoria_tab_t((select ref(c) from categorias c where nome='FEUP')),
topico_tab_t((select ref(t) from topicos t where titulo='Diogo Pereira'), -- which is an object of the subtype "contacto_t"
(select ref(t) from topicos t where titulo='Comecar a dissertacao'), -- which is an object of the subtype "memo_t"
(select ref(t) from topicos t where titulo='Apresentar Dissertacao'), -- which is an object of the subtype "tarefa_t"
(select ref(t) from topicos t where titulo='Reuniao com Orientador da Dissertacao')), -- which is an object of the subtype "anotacao_t"
TO_DATE('2018/08/13', 'YYYY/MM/DD'),
0,
'Dissertacao all over again'));
So, I have to build a query or even a PL/SQL block that returns me all the rows of the table "topicos" that contains at least, in the nested table "referencias", one instance object for each of this 4 subtypes mentioned above. Ideally this query would return me that row (mentioned in the above INSERT).
Best regards and hope you're having a good Worker's Day! ;)
You have a mistake in your DDL code. You are creating a base type topico_t and then some subtypes under that type, but you're creating a single table of base type objects only. The problem with this is that you're expecting that table to hold objects of any subtype, which will not be the case due to what is known as object slicing. The table you've created has only the columns which correspond to the fields you've defined for the base type.
Therefore, you need to create tables for all of the subtypes which you will eventually instantiate. You should only create a table for the base type if it makes sense for that type to be instantiated, that is, if an object of the base type which doesn't belong to any of the subtypes could exist.
After doing this, the query you're trying to write should use the function TREAT. Note that, according to the documentation, this function returns NULL when the expression is not of the type you're trying to cast to, so the query you need to write should be as simple as testing if there is at least one row with a non-null result field when selecting from the nested table and attempting to cast to each of the subtypes you've created. Check the example on the documentation to see how to use this function.

How to CREATE TABLE with disjoint relationship in SQL

I am trying to create a table using a disjoint subtype relationship.
For example, if the Supertype is furniture, and I have 3 Subtypes of furniture: chair, couch, and table.
Then:
CREATE TABLE Furniture
(order_num NUMBER(15), desc VARCHAR2(20), type VARCHAR2(10));
How do I make an option to pick type of chair, couch or table?
You can use REFERENCES in the CREATE TABLE.
CREATE TABLE Furniture_SubTypes
(
sub_type VARCHAR(10) PRIMARY KEY
);
INSERT INTO Furniture_SubTypes VALUES ('Chair');
INSERT INTO Furniture_SubTypes VALUES ('Couch');
INSERT INTO Furniture_SubTypes VALUES ('Table');
CREATE TABLE Furniture
(
order_num NUMBER,
description VARCHAR(20),
sub_type REFERENCES Furniture_SubTypes(sub_type)
);
Use a check constraint:
CREATE TABLE Furniture (
order_num NUMBER(15),
description VARCHAR2(20),
type VARCHAR2(10),
check (type in ('chair', 'couch', 'table'))
);
Note that desc is a poor choice for a column name, because it is a keyword in SQL (used for order by).

Oracle object relational DB: Access columns of referenced rows

I have some tables and need to create object views on top of them.
CREATE TABLE Person (
Nr NUMBER(4) PRIMARY KEY,
Name VARCHAR2(15));
CREATE TABLE Professor (
Nr NUMBER(4) PRIMARY KEY,
HabilThema VARCHAR2(30));
I also created types:
CREATE OR REPLACE TYPE Person_Typ AS OBJECT(
Nr INTEGER,
Name VARCHAR2(15)
);
CREATE OR REPLACE TYPE Professor_Typ AS OBJECT(
Nr INTEGER,
Habilthema VARCHAR2(30),
Person REF Person_Typ
);
As you can see there is a reference from a professor row to a person row. The view of the professors now should also include the columns of the person. Something like:
CREATE VIEW People OF Person_Typ
WITH OBJECT IDENTIFIER(Nr) AS
SELECT p.Nr, p.Name FROM Person p;
CREATE VIEW Professors OF Professor_Typ
WITH OBJECT IDENTIFIER(Nr) AS
SELECT p.Nr, p.Habilthema, p.Person.Name, MAKE_REF(People,p.Nr) FROM Professor p;
^
|_ Name of professor from Person table
But this does not work:
"P"."PERSON"."NAME" invalid identifier
Can this even be achieved by an object view? How?

How do I insert data into object tables that have refs to others?

I'm new in Oracle and I really don't have a clear idea how to do this.
The database is this one...
CREATE OR REPLACE TYPE personUdt4 AS OBJECT(
pid varchar(11),
firstName varchar(20),
lastName varchar(20),
dob date)
NOT FINAL;
/
CREATE OR REPLACE TYPE locationUdt4 AS OBJECT(
street varchar(30),
bldg varchar(5),
room varchar(5))
NOT FINAL;
/
CREATE TYPE departmentUdt4;
/
CREATE TYPE studentUdt4;
/
CREATE TYPE facultyUdt4;
/
CREATE OR REPLACE TYPE campusClubUdt4 AS OBJECT(
cId number,
name varchar(50),
location locationUdt4,
phone varchar(12),
advisor REF facultyUdt4,
members REF studentUdt4)
NOT FINAL;
/
CREATE OR REPLACE TYPE facultyUdt4 UNDER personUdt4(
rank varchar(10),
advisorOf REF campusClubUdt4,
worksIn REF departmentUdt4,
chairOf REF departmentUdt4)
NOT FINAL;
/
CREATE OR REPLACE TYPE studentUdt4 UNDER personUdt4(
status varchar(10),
memberOf REF campusClubUdt4,
major REF departmentUdt4)
NOT FINAL;
/
CREATE OR REPLACE TYPE studentUdtList4 AS VARRAY(1000) of studentUdt4;
/
CREATE OR REPLACE TYPE facultyUdtList4 AS VARRAY(50) of facultyUdt4;
/
CREATE OR REPLACE TYPE departmentUdt4 AS OBJECT(
code varchar(3),
name varchar(40),
deptChair REF facultyUdt4,
MEMBER FUNCTION getStudents RETURN studentUdtList4,
MEMBER FUNCTION getFaculty RETURN facultyUdtList4)
NOT FINAL;
/
CREATE TYPE BODY departmentUdt4 as
member function getStudents return studentUdtList4
end func;
member function getFaculty return facultyUdtList4
end func;
end;
/
CREATE TABLE person4 OF personUdt4(
primary key (pid));
/
CREATE TABLE faculty4 OF facultyUdt4;
/
CREATE TABLE student4 OF studentUdt4;
/
CREATE TABLE department4 OF departmentUdt4(
primary key (code));
/
CREATE TABLE campusClub4 OF campusClubUdt4(
primary key (cid)
);
INSERT INTO student4
(pid, firstname, lastname, dob, status, memberOf, major)
VALUES
('10','alex','smith','31-may-98','FRESH', '10', '11');
COMMIT;
It'll be great if someone can help me D:
(This is all based on my very limited knowledge of Oracle's object-relational technology. Some of it may be wrong, and there's likely a simpler way to do this.)
As I understand it, a REF must point to an actual row. You must create some data before you can create some data. Since there are so many circular references you'll have to go back later and update everything. But hopefully this is enough to at least get you started.
--Create some rows to reference.
insert into campusClub4(cid) values(1);
insert into department4(code) values('A');
--Insert regular columns first.
insert into student4(pid, firstName, lastName, dob, status)
values('10', 'alex', 'smith', to_date('31-MAY-1998', 'DD-MON-YYYY'), 'FRESH');
--Add references with an update.
update student4
set memberOf = (select ref(campusClub) from campusClub4 campusClub where cid = 1)
,major = (select ref(department) from department4 department where code = 'A')
where pid = '10';
--Verify data
select pid, firstname, lastname, dob, status, deref(memberOf), deref(major) from student4;
--This would be a simpler method, but it doesn't work and I don't understand why.
insert into student4(pid, firstName, lastName, dob, status)
values('10', 'alex', 'smith', to_date('31-MAY-1998', 'DD-MON-YYYY'), 'FRESH'
,(select ref(campusClub) from campusClub4 campusClub where cid = 1)
,(select ref(department) from department4 department where code = 'A')
);
But I strongly recommend that you NEVER DO THIS. Inserting data into a table should not be this difficult. Object Relational databases are probably a bad idea. And Oracle's implementation of it sucks. You'll get ORA-600 errors and "invalid" tables all over the place with this stuff (e.g. I just got an ORA-600 from cross joining campusClub4 and department4 with only one row in each). And nobody will know how to use your data.