SQL error creating views (with nested tables) - sql

I'm having trouble with a very basic example of creating a view.
These are the tables:
Create or replace type LEVEL_T as object(
Duties Varchar2(50),
Charge Number(10),
NO Date,
LIDZ Date
);
Create or replace type LEVELS_T as table of LEVEL_T;
Create table BOTS(
Bot_ID Number(10) constraint pk_bots primary key,
Name Varchar2(30),
Class Varchar2(30),
Start_date Date,
Levels LEVELS_T
) nested table Levels store as BOTS_LEVELS_COL;
Object:
Create or replace type OBJ_DATE as object(
Name Varchar2(30),
Class Varchar2(30),
Duties Varchar2(30),
Charge Number(10),
NO Date,
LIDZ Date,
MEMBER function WORKS(P_DATE in Date) return number
);
Create or replace type body OBJ_DATE as
MEMBER function WORKS(p_date in Date) return number is
begin
if ((p_date >= self.NO AND p_date < self.LIDZ) OR
(self.LIDZ IS NULL AND p_date >= self.NO)) then
return 1;
else
return 0;
end if;
end WORKS;
end;
And now i'm trying to make a view out of all this by:
Create or replace view VIEW_WORK of OBJ_DATE with object identifier(Name) as
Select A.Name, A.Class, B.Duties, B.Charge, B.NO, B.LIDZ
From BOTS A, table(A.Levels) B;
And keep getting an error starting at line 1: ORA-01730: invalid number of column names specified; 01730. 00000 - "invalid number of column names specified".
Was playing around with this for a bit and could only manage to get it to work when removing the part around "object identifier", but then calling the function WORKS (a bit ironical) doesn't when attempted to test the view. I'm completely stuck right now, so any tips on what am I doing wrong?

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') )

Invalid Identifier on Where Clause PL/SQL

Trying to perform a query on data in a table. The query is 'Give album title, album release date and album price of all Neil Young’s albums released after 1st January 2015.'
The relevant structure of the table (excluding other parts) is as follows:
create or replace type artist_type as object
(artistName varchar(50),
artistRole varchar(25))
/
create type artist_array_type
as varray(5) of artist_type
/
create or replace type album_type as object
(albumTitle varchar(50),
albumPlaytime number(3), -- minutes
albumReleaseDate date,
albumGenre varchar(15),
albumPrice number(9,2),
albumTracks number(2),
albumArtists artist_array_type,
albumReviews review_table_type,
member function discountPrice return number,
member function containsText (pString1 varchar2, pString2 varchar2) return integer)
not instantiable not final
/
The below is my current query,
select a.albumtitle, a.albumreleasedate, a.albumprice
from albums a
where a.albumartists.artist_type.artistname = 'Neil Young'
and a.albumreleasedate >= '1-Jan-2015';
however upon attempting to execute it in Oracle SQL Developer I get the error:
ORA-00904: "A"."ALBUMARTISTS"."ARTIST_TYPE"."ARTISTNAME": invalid identifier
00000 - "%s: invalid identifier"

Adding Constraints to VARRAY UDT inside a Table in PLSQL

I'm stuck figuring out how to add some constraints to the attributes of my UDTs.
Here's my situation. I've got a UDT that represents the daily number of hours an employee should work (forgive me for using Italian names).
CREATE OR REPLACE TYPE TURNO_GIORNALIERO AS OBJECT(
GIORNO VARCHAR(15),
ORA_INIZIO DATE,
NUMERO_ORE NUMBER,
MEMBER FUNCTION getOreLavoro RETURN NUMBER
);
Then I defined new Type as a VARRAY(5) of TURNO_GIORNALIERO, named TURNI_SETTIMANALI (that is a Varray containing the number of hours an employee should work for each day of the week).
CREATE OR REPLACE TYPE TURNI_SETTIMANALI AS VARRAY(5) OF TURNO_GIORNALIERO;
In the end, I've created the table that contains TURNI_SETTIMANALI.
CREATE TABLE TURNO_LAVORO(
ID_TURNO CHAR(9) PRIMARY KEY,
TURNO TURNI_SETTIMANALI NOT NULL,
);
What I want to do is to add a constraint to the table TURNO_LAVORO in order to check if NUMERO_ORE (defined in TURNO GIORNALIERO) is greater than 5.
Could someone please help me? I've tried several solutions but nothing worked.
I doubt it is possible in check constraint. Documentation says:
Conditions of check constraints cannot contain the following
constructs:
Calls to user-defined functions
Nested table columns or attributes
You could use trigger however. Test types and table:
create or replace type daily_cycle
as object(day varchar(15), hour_start date, hour_count number);
create or replace type week_cycle
as varray(5) of daily_cycle;
create table test(id int, shift week_cycle);
Trigger:
create or replace trigger hour_check before insert on test for each row
begin
for i in 1..:new.shift.count() loop
if :new.shift(i).hour_count < 5 then
raise_application_error(-20001,'hours less than 5');
end if;
end loop;
end;
First insert works, second no:
insert into test values (1,
week_cycle(daily_cycle('a', date '2017-12-01', 5),
daily_cycle('b', date '2017-12-02', 8) ) );
insert into test values (2,
week_cycle(daily_cycle('a', date '2017-12-03', 3),
daily_cycle('b', date '2017-12-04', 12),
daily_cycle('b', date '2017-12-05', 7) ) );

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.

oracle11g sql: Warning: Type created with compilation errors

I'm trying to create a supertype customer service and subtype agent and supervisor, so they can inherent values however when I try to run this in oracle sql: a message comes up
Warning: Type created with compilation errors.
What is wrong with the code below?
Create or replace type customer_s_type as object (
csID number,
csName varchar(15),
csType number ) NOT FINAL;
Create or replace type supervisor_type UNDER customer_s_type ( title varchar (10) );
Create or replace type agent_type UNDER customer_s_type (title varchar (10));
Create table supervisor of supervisor_type (
CONSTRAINT supervisor_PK PRIMARY KEY (csID));
Create table agent of agent_type (CONSTRAINT agent_PK PRIMARY KEY (csID));
create table customer_service(
csID number(10),
csType number(10),
constraint supervisor_pk primary key(csID) );
You can use show errors in SQL*Plus or SQL Developer, or select * from user_errors, to see the error details.
Since you've shown six commands and the warning is about one of the first three (since it refers to type), and they appear OK independently apart from the constraint pointed put in comments, it looks like the whole script is being imterpreted as one command. It depends on your client settings, but you probably just need to seperate the commands with a / to cause them to execute. Becuase types can include PL/SQL the ; isn't treated as a statement seperator. So:
Create or replace type customer_s_type as object (
csID number,
csName varchar(15),
csType number ) NOT FINAL;
/
Create or replace type supervisor_type UNDER customer_s_type ( title varchar (10) );
/
Create or replace type agent_type UNDER customer_s_type (title varchar (10));
/
Create table supervisor of supervisor_type (
CONSTRAINT supervisor_PK PRIMARY KEY (csID));
Create table agent of agent_type (CONSTRAINT agent_PK PRIMARY KEY (csID));
create table customer_service(
csID number(10),
csType number(10),
constraint customer_service_pk primary key(csID) );