Alter Object So That Spec Is Organized? - sql

I'm using PL/SQL and I'd like to alter a type by adding an attribute. I need to alter as there are table dependencies that prevent replacing. When I use the following code.
create or replace type example_type as object
(
num_var number
);
alter type example_type add attribute (varchar2_var varchar2(10));
It creates a spec with that exact code.
Is there a way to make it so that the spec looks like
create or replace type example_type as object
(
num_var number,
varchar2_var varchar2(10)
);
Instead?

Related

Changing the datatype with a custom type in postgres custom data type

I have a custom type in Postgres DB called money_with_currency Created as:
CREATE TYPE public.money_with_currency AS (currency_code char(3), amount numeric);
We want to change the type of currency_code from char(3) to varchar.
I thought the code would be something like:
ALTER TYPE public.money_with_currency ALTER ATTRIBUTE currency_code SET DATA TYPE varchar;
But got an error:
ALTER TYPE public.money_with_currency ALTER ATTRIBUTE currency_code SET DATA TYPE varchar;\n"
** (Postgrex.Error) ERROR 0A000 (feature_not_supported) cannot alter type "money_with_currency" because column "prog_fees.amount" uses it
Any thoughts if there is a solution without having to do manual migration to all columns using the type?
First create another custom type and use an alter table query to change the column type of the prog_fees. Then alter the type of public.money_with_currency. Then again execute a alter query to table using public.money_with_currency type. Then it will work
You will need to create a new type with the desired structure. But as there is no direct cast from the old to the new type, you need to use a row constructor when altering the type of the existing column:
CREATE TYPE money_with_currency_new AS (currency_code text, amount numeric);
alter table prog_fees
alter column amount type money_with_currency_new
using ((amount).currency_code, (amount).amount)::money_with_currency_new;
Note the parentheses around the column name when referencing the type's attributes. They are required.
After that you can drop the old type and rename the new type to the old name:
drop type money_with_currency;
alter type money_with_currency_new
rename to money_with_currency;

Oracle Object-Relational - PLS-00538 error and PLS-00539 error

Type definition:
CREATE TYPE INTERVENTO_TY AS OBJECT(
Testo VARCHAR2(20),
Timestmp DATE
) NOT FINAL;
CREATE TYPE COMMENTO_TY UNDER INTERVENTO_TY(
Ordine VARCHAR2(20)
);
CREATE TYPE POST_TY UNDER INTERVENTO_TY(
Titolo VARCHAR2(20),
MEMBER PROCEDURE AddCom(Ordine VARCHAR2, Testo VARCHAR2, Timestmp Date)
);
CREATE TYPE AUTORE_TY AS OBJECT(
Nome VARCHAR2(20),
Cognome VARCHAR2(20),
IdAutore INT
);
CREATE TYPE MEDIA_TY AS OBJECT(
Tipo VARCHAR2(20),
Nome VARCHAR2(20),
IdMedia INT,
Titolo VARCHAR2(20)
);
CREATE TYPE SCRIVE_INTERVENTO AS TABLE OF REF INTERVENTO_TY;
CREATE TYPE DI_AUTORE AS TABLE OF REF AUTORE_TY;
ALTER TYPE INTERVENTO_TY ADD ATTRIBUTE DI DI_AUTORE CASCADE;
ALTER TYPE AUTORE_TY ADD ATTRIBUTE SCRIVE SCRIVE_INTERVENTO CASCADE;
CREATE TYPE IN_INTERVENTO AS TABLE OF REF INTERVENTO_TY;
CREATE TYPE CONTIENE_MEDIA AS TABLE OF REF MEDIA_TY;
ALTER TYPE INTERVENTO_TY ADD ATTRIBUTE CONTIENE CONTIENE_MEDIA CASCADE;
ALTER TYPE MEDIA_TY ADD ATTRIBUTE IN_INT IN_INTERVENTO CASCADE;
CREATE TYPE COMMENTATO_POST AS TABLE OF REF COMMENTO_TY;
ALTER TYPE COMMENTO_TY ADD ATTRIBUTE A REF POST_TY CASCADE;
ALTER TYPE POST_TY ADD ATTRIBUTE COMMENTATO COMMENTATO_POST CASCADE;
CREATE TABLE AUTORE_TAB OF AUTORE_TY
NESTED TABLE SCRIVE STORE AS SCRIVE_NESTED;
CREATE TABLE INTERVENTO_TAB OF INTERVENTO_TY
NESTED TABLE DI STORE AS DI_NESTED
NESTED TABLE CONTIENE STORE AS CONTIENE_NESTED;
CREATE TABLE MEDIA_TAB OF MEDIA_TY
NESTED TABLE IN_INT STORE AS IN_INT_NESTED;
I'm trying to write an object procedure that creates a new instance of COMMENTO_TY, adds it to the COMMENTO_TAB table and the COMMENTATO nested table of POST_TY, but it gives me the following error:
CREATE OR REPLACE TYPE BODY Post_ty AS
MEMBER PROCEDURE addComm(commento VARCHAR2, ordine NUMBER, IdAut INTEGER) AS
NuovoCommento REF Commento_ty;
BEGIN
INSERT INTO Intervento_tab I
VALUES(Commento_ty(commento, SYSTIMESTAMP,
DI_AUTORE(
(SELECT REF(A) FROM AUTORE_TAB A WHERE IdAutore = IdAut)
),
CONTIENE_MEDIA(),
ordine,
(SELECT TREAT(REF(I) AS REF POST_TY)
FROM INTERVENTO_TAB I
WHERE VALUE(I) IS OF (POST_TY) AND
I.TIMESTMP = SELF.TIMESTMP)))
RETURNING REF(I) INTO NuovoCommento;
INSERT INTO TABLE(SELECT TREAT(VALUE(I) AS POST_TY).COMMENTATO
FROM INTERVENTO_TAB I
WHERE VALUE(I) IS OF (POST_TY)
AND I.TIMESTMP = SELF.TIMESTMP)
VALUES(NuovoCommento);
END addComm;
END;
/
PLS-00538: subprogram or cursor 'ADDCOM' is declared in an object type specification and must be defined in the object type body at line 3
PLS-00539: subprogram 'ADDCOMM' is declared in an object type body and must be defined in the object type specification at line 2
You have two errors:
PLS-00538: subprogram or cursor 'ADDCOM' is declared in an object type specification and must be defined in the object type body
and
PLS-00539: subprogram 'ADDCOMM' is declared in an object type body and must be defined in the object type specification
Notice how one is spelt ADDCOM and the other is ADDCOMM; you need to make sure the member procedure has the same name in the specification and the body.

PLSQL TYPE modifications

I have created the below type,
create or replace
TYPE MSSINT.TEST_TYPE
AS OBJECT
(service_phone_num varchar2(15),
name_last varchar2(50),
name_first varchar2(50));
Now I need to change the dataype of service_phone_num to NUMBER.
Can we achieve this using the below command or something like below?
ALTER TYPE MSSINT.TEST_TYPE MODIFY ATTRIBUTE (service_phone_num NUMBER) CASCADE;
Execute the following:
create or replace
TYPE MSSINT.TEST_TYPE
AS OBJECT
(service_phone_num number(15),
name_last varchar2(50),
name_first varchar2(50));
Should work, as you have create or replace.
Use the command
create or replace
TYPE MSSINT.TEST_TYPE
AS OBJECT
(service_phone_num number,
name_last varchar2(50),
name_first varchar2(50));
Replace modify your type.

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.

Invalid Identifier error for scope

I have created customer_ty object which includes a nested table called "deposits".
CREATE TYPE deposit_ty as object(
depNo number,
depCategory ref depcategory_ty,
amount number,
period number
)
/
This 'depCategory' reference depcategory_ty in another table called 'depcategory_tbl'.
CREATE TYPE deposit_ntty as table of depcategory_ty
/
CREATE TYPE address_ty as varray(3) of varchar2(20)
/
CREATE TYPE customer_ty as object(
custId varchar2(4),
custName varchar2(10),
address address_ty,
dob date,
deposits deposit_ntty
)
/
CREATE TABLE customer_tbl of customer_ty(
custId primary key)
nested table deposits store as cli_deposit_tbl
/
alter table cli_deposit_tbl
add scope for (depCategory) is depcategory_tbl
/
The problem appears when I try to add a scope for table. it says;
add scope for (depCategory) is depcategory_tbl
*
ERROR at line 2:
ORA-0094:"DEPCATEGORY":Inavalid Identifier
All the identifiers are correct. What is wrong with this?
It looks like you've defined deposit_ntty incorrectly, and meant it to be:
CREATE TYPE deposit_ntty as table of deposit_ty
/
With that change, your alter now gets:
alter table cli_deposit_tbl
add scope for (depCategory) is depcategory_tbl
/
ORA-22892: scoped table "DEPCATEGORY_TBL" does not exist in schema "PUBLIC"
You may already have that but it isn't shown; with it there the alter works:
CREATE TABLE depcategory_tbl of depcategory_ty;
Table DEPCATEGORY_TBL created.
alter table cli_deposit_tbl
add scope for (depCategory) is depcategory_tbl
/
Table CLI_DEPOSIT_TBL altered.