Alter Type: add attribute if it doesn't already exist - oracle

Is there a way to alter an object type to add an attribute only if it doesn't already exist? I am writing a script that will be run on multiple databases. I'm trying to avoid unnecessary PLS-00410 errors (duplicate fields in RECORD,TABLE or argument list are not permitted).
Something like the following:
ALTER TYPE employee
ADD ATTRIBUTE --IF NOT EXISTS
(address2 VARCHAR2(30))
CASCADE;
If there is no elegant inline solution like the above, is there a system table I can look at? ALL_TYPES only lists the number of attributes per type, not the specific attributes.

ALL_TYPE_ATTRS appears to be what you're looking for. It's a child of ALL_TYPES for OBJECT types.

Related

How can I create a table with same attributes of a View another system delivers me?

An external system granted to my system a view named V_EXT so that I can make selections on it, reading all its content:
SELECT *
FROM V_EXT;
this view has a lot of fields and I would like to create an empty table in my system with the exactly same attributes of this view (same names and same types). Is there a way to do this without simply guessing from the content I received what each attribute is?
I am using Oracle SQL Developer.
With Code.
create table objects_copy2
as
select *
from all_objects
where 1=2; -- add this line if you want NO data, otherwise you get all the data too
With SQL Developer specifically, it's actually harder. You would need to find the underlying OBJECT(s) used in the query. Then look up those data types, and manually build out your CREATE TABLE statement.
CREATE TABLE AS SELECT is the way to go. (Docs)
Note there are some limitations, for example this won't pick up Identity Column definitions from the source table used in the view.
An example:

PL/SQL Record and Table Variables inchanged

I am new to Oracle PL/SQL and have been given some code I am being asked to modify. I have been looking through the oracle documentation and think I know what it is doing but would like to get a verification as to if my understanding is correct or not.
Here is the code:
TYPE array_rec_type IS RECORD (gla_sub tblName.id%type);
v_closes_sc array_rec_type;
TYPE v_sc_type is TABLE OF v_closes_sc%TYPE INDEX BY BINARY_INTEGER;
sc_array v_sc_type;
Here is what I believe is being declared here:
TYPE array_rec_type IS RECORD (gla_sub tblName.id%type);
It looks like a collection is being declared using the column type from the id column from the tblName table. Which could be a number or UUID, etc.
v_closes_sc array_rec_type;
A variable of the newly created type is being created
TYPE v_sc_type is TABLE OF v_closes_sc%TYPE INDEX BY BINARY_INTEGER;
A new type is being created using the collection (Record) previously created a template for the table. The table will have a single column of ID.
sc_array v_sc_type;
A new variable is being created to hold the new table variable.
A record is not a collection, so your explanation is slightly confused. From the docs (which you've probably already looked at:
In a collection, the internal components always have the same data type, and are called elements. ... To create a collection variable, you either define a collection type and then create a variable of that type or use %TYPE.
In a record, the internal components can have different data types, and are called fields. You can access each field of a record variable by its name ... To create a record variable, you either define a RECORD type and then create a variable of that type or use %ROWTYPE or %TYPE.
So looking at what you said:
Here is what I believe is being declared here:
TYPE array_rec_type IS RECORD (gla_sub tblName.id%type);
This is a record, not a collection. In this case it has a single field called gla_sub which is indeed being declared using the data type of the id column from the tblName table. The use of %type means that, to some extent, you don't need to know what the data type actually is, and you may not have to change your code if that changes (if the size of a varchar2 column is increased, for instance).
v_closes_sc array_rec_type;
Correct - a variable of the newly created type is being created.
TYPE v_sc_type is TABLE OF v_closes_sc%TYPE INDEX BY BINARY_INTEGER;
This is a collection, specifically an associative array. It's a sparse array whose members are instance of the record type declared above, with a numeric index. That could also be declared using the type directly, as:
TYPE v_sc_type is TABLE OF array_rec_type INDEX BY BINARY_INTEGER;
sc_array v_sc_type;
Correct - a new variable is being created of that just-declared table type.
Having a record type with a single field seems a bit pointless, as you could have a collection based on the table column data type. Your existing code will be expecting that structure though, so changing it isn't quite trivial.

Oracle PLSQL Alter/Drop Attributes of Object Type

I am new to Oracle PLSQL and have to Alter an Object Type. I´ve made many mistakes with the data types of the new Columns, so I had to drop them and altered them a second time.
For example, I did this:
ALTER TYPE testObjectType ADD ATTRIBUTE (Prename VARCHAR2(50))
ALTER TYPE testObjectType DROP ATTRIBUTE Prename
ALTER TYPE testObjectType ADD ATTRIBUTE (Prename VARCHAR2(50 CHAR))
Now below the "Create or Replace" - Code of the Object there are many lines of code about adding & dropping Attributes. I´ve to try to simply delete this lines but the changes don't work at all. How can I tidy up my Object-Type? (I'm using Oracle SQL Developer).
You need to reset it so it is no longer treated as an evolved type:
alter type testobjecttype reset;
Then you can rebuild it with:
create or replace type testobjecttype as object
( prename varchar2(50 char) );
(plus any other attributes etc it should have).
btw there isn't much point naming database objects in CamelCase as the database ignores it, and schema browsers will just list it in uppercase (because that's how the dictionary stores names), which can become hard to read without word separators. (And shouldn't it be TestObjectType anyway?) There is a better case for it in naming program variables, although they are case-insensitive as well, so it's probably simplest and cleanest to just code in lowercase.

Oracle PL/SQL table of parent object type breaks when I add another inheriting child object type

I am using custom object types with Oracle PL/SQL, including several object types that inherit from a parent object. I have a TP_DOCUMENTS parent object, and child document types, such as TP_PUBLICATION, TP_CONTRACT, etc. We successfully created a table of TP_DOCUMENT and have added records of TP_PUBLICATION, TP_CONTRACT, and other child document records. However, I needed to create an additional type of document. Once I did this, it broke the DOCUMENTS table. How can I create additional child types, without breaking the table of the parent object (making me lose all the data previously contained in the parent object table!!)?
Here is some of my code:
create or replace TYPE "TP_DOCUMENT" AS OBJECT
(
...fields go here
) NOT FINAL
create or replace TYPE "TP_PUB_INSTRUCTION" UNDER TP_DOCUMENT()
CREATE TABLE DOCUMENTS OF TP_DOCUMENT
After creating these types (and others with additional fields), I created the table DOCUMENTs as shown above. I tried to create another sub-type, and the DOCUMENTS table broke.
MORE INFORMATION:
The error code message is as follows:
ORA-04063: table/view has errors
Cause: Attempt to execute a stored procedure or use a view that has errors. For stored procedures, the problem could be syntax errors or references to other, non-existent procedures. For views, the problem could be a reference in the view's defining query to a non-existent table. Can also be a table which has references to non-existent or inaccessible types.
Action: Fix the errors and/or create referenced objects as necessary.
Thank you!
UPDATE WITH ANSWER FROM COMMENTER BELOW:
I had unfortunately dropped a Sub-Type using the Force option. That likely was the cause for why my Documents table was corrupted. In the future, I will use the Validate command (see answer below).
Instead of FORCE you should use the VALIDATE option when dropping types:
VALIDATE
If you specify VALIDATE when dropping a type, then Oracle Database
checks for stored instances of this type within substitutable columns
of any of its supertypes. If no such instances are found, then the
database completes the drop operation.
This clause is meaningful only for subtypes. Oracle recommends the use
of this option to safely drop subtypes that do not have any explicit
type or table dependencies.
Here's an example:
create or replace type tp_document as object
(
a number
) not final;
create or replace type tp_pub_instruction under tp_document();
create table documents of tp_document;
--This fails with this error message:
--ORA-02303: cannot drop or replace a type with type or table dependents
drop type tp_pub_instruction;
--This works since there's no data with that type.
drop type tp_pub_instruction validate;

Can I drop/add attribute without consequences? Oracle Object Type

I have an OBJECT_TYPE with ATTRIBUTE varchar2(200). There many other objects referencing this one. I need to reduce the length of the attribute to varchar2(50). I know I cannot do it directly, so I found this way:
ALTER TYPE CUSTOMER DROP ATTRIBUTE name INVALIDATE;
ALTER TYPE CUSTOMER ADD ATTRIBUTE name varchar2(50) CASCADE;
The question is: is there anything that could be broken after the dropping/creating of the attribute? Is it correct to use the INVALIDATE option instead of CASCADE in the DROP statement? I don't want to loose anything - relations or data.
Is there a reason the following is not used:
ALTER TYPE CUSTOMER MODIFY ATTRIBUTE name VARCHAR2(50);
I have run into compatibility problems when using types and dropping an attribute especially if there are tables and data defined using the types. This is one reason I avoid basing tables and views on the data types. The change in the length would invalidate the table and any rows where the associated data exceeds 50. If the other objects are just types and are not used in views and tables then the alter type above should work fine. And you may need to recompile any types. Keep in mind that the type is becoming more restrictive and how it may affect any associated data.

Resources