I'm develop a simple app for learn about oracle and database object-relational with objects and varrays... I did the next code:
this is my varrays
SQL> create or replace type software_va as varray(3) of varchar2(30);
2 /
here is an object that I created:
SQL> create or replace type cargo1 as object(
2 id_cargo number,
3 nom_cargo varchar2(20),
4 suc ref sucursal);
5 /
when I try to create the table at this way:
SQL> create table cargos of cargo1(
2 primary key(id_cargo),
3 manejosoft software_va);
I got this error:
ERROR en line 3:
ORA-02330: datatype specification not allowed
I don't understand why I got this error and don't know if I have something wrong
If you want a relational table with both object and varray columns, this should work, and still has a primary key based on the object's ID:
create table cargos
(
cargo cargo1,
manejosoft software_va,
constraint cargos_pk primary key (cargo.id_cargo)
);
Table created.
insert into cargos values (cargo1(1, 'test'), software_va('a', 'b', 'c'));
1 row created.
insert into cargos values (cargo1(1, 'dup test'), software_va('d', 'e', 'f'));
insert into cargos values (cargo1(1, 'dup test'), software_va('d', 'e', 'f'))
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.CARGOS_PK) violated
select * from cargos;
CARGO(ID_CARGO, NOM_CARGO)
--------------------------------------------------------------------------------
MANEJOSOFT
--------------------------------------------------------------------------------
CARGO1(1, 'test')
SOFTWARE_VA('a', 'b', 'c')
select c.cargo.nom_cargo
from cargos c
where c.cargo.id_cargo = 1;
CARGO.NOM_CARGO
--------------------
test
If you wanted an object table then you couldn't have the varray column as mentioned in comments:
create table cargos of cargo1
(
primary key(id_cargo)
);
Related
I am trying to come up with a way to make sure that when a table is updated, that a certain condition is met. Can this be done in a trigger? I have made the following two tables, storeTable and employeeTable.
I need to make sure that when storeManager is updated in the storeTable, that the employee has a storeID that matches the store in which I am trying to update the storeManager. (employee cannot be manager of a store he does not work at)
In addition, I need to make sure that the employee exists in the employeeTable. I was thinking some sort of CASE statement would be best, but dont know how this could be enforced by a trigger.
I was thinking about morphing the "Foreign Key Trigger for Child Table" trigger example from https://docs.oracle.com/cd/B12037_01/appdev.101/b10795/adfns_tr.htm#1007172 but I could not figure out how to change this to fit my specific need. Any help is much appreciated.
For context, the current keys are:
storeTable:
storeID PRIMARY KEY
employeeTable:
empID PRIMARY KEY
storeID FOREIGN KEY REFERS TO storeTable.storeID
To me, it seems that constraints can do the job. You don't need triggers.
Here's how. First, create tables without any constraints. Then add them, both primary and foreign key ones which will be deferrable (otherwise you wouldn't be able to insert any rows as parent keys don't exist yet).
SQL> create table employee
2 (empid number,
3 fname varchar2(10),
4 storeid number
5 );
Table created.
SQL> create table store
2 (storeid number,
3 storename varchar2(20),
4 storemanager number
5 );
Table created.
SQL>
SQL> alter table employee add constraint pk_employee primary key (empid, storeid);
Table altered.
SQL> alter table store add constraint pk_store primary key (storeid);
Table altered.
SQL>
SQL> alter table store add constraint fk_store_emp foreign key (storemanager, storeid)
2 references employee (empid, storeid)
3 deferrable initially deferred;
Table altered.
SQL> alter table employee add constraint fk_emp_store foreign key (storeid)
2 references store (storeid)
3 deferrable initially deferred;
Table altered.
SQL>
Now let's add some data: initial insert into employee will be OK until I commit - then it'll fail because its store doesn't exist yet:
SQL> insert into employee values (1, 'John' , 1);
1 row created.
SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (SCOTT.FK_EMP_STORE) violated - parent key not
found
SQL>
But, if I don't commit and pay attention to what I'm entering (i.e. that referential integrity is maintained), it'll be OK:
SQL> insert into employee values (1, 'John' , 1);
1 row created.
SQL> insert into employee values (2, 'Matt' , 2);
1 row created.
SQL> insert into store values (1, 'Santa Clara', 1);
1 row created.
SQL> insert into store values (2, 'San Francisco', 2); --> note 2 as STOREID
1 row created.
SQL> commit;
Commit complete.
SQL> select * From employee;
EMPID FNAME STOREID
---------- ---------- ----------
1 John 1
2 Matt 2
SQL> select * From store;
STOREID STORENAME STOREMANAGER
---------- -------------------- ------------
1 Santa Clara 1
2 San Francisco 2
SQL>
See? So far so good.
Now I'll try to modify STORE table and set its manager to John who works in storeid = 1 which means that it should fail:
SQL> update store set storemanager = 1
2 where storeid = 2;
1 row updated.
SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (SCOTT.FK_STORE_EMP) violated - parent key not
found
SQL>
As expected.
Let's now add emplyoee ID = 6, Jimmy, who works in storeid = 2 and set him to be manager in San Francisco (storeid = 2):
SQL> insert into employee values (6, 'Jimmy', 2);
1 row created.
SQL> update store set storemanager = 6
2 where storeid = 2;
1 row updated.
SQL> commit;
Commit complete.
SQL>
Yey! It works!
As you can see, no triggers needed.
Note that - if you want to drop any of those tables - you'll fail as they are referenced by each other:
SQL> drop table store;
drop table store
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
SQL> drop table employee;
drop table employee
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
SQL>
It means that you'd first have to drop foreign key constraints, then drop tables:
SQL> alter table employee drop constraint fk_emp_store;
Table altered.
SQL> alter table store drop constraint fk_store_emp;
Table altered.
SQL> drop table store;
Table dropped.
SQL> drop table employee;
Table dropped.
SQL>
That's all, I guess.
create or replace TYPE PDV AS OBJECT
( percentage NUMBER(4,2),
MEMBER FUNCTION get_percentage RETURN NUMBER
) INSTANTIABLE NOT FINAL;
create or replace TYPE BODY PDV AS
MEMBER FUNCTION get_percentage RETURN NUMBER AS
BEGIN
return SELF.percentage;
END get_percentage;
END;
I have table Product (productID, name, description, percentage)
When I insert this in the database, it should be saved in the table Product:
insert into Product VALUES (1, 'Table', 'Brown table for six people.Made of oak', PDV(20.00));
When I insert this into the database, an error should occur:
insert into Product VALUES (1, 'Table', 'Brown table for six people.Made of oak', PDV(130.20));
I want to make distinct type with condition - percentage must be between 0 and 100. Where to put that condition?
percentage must be between 0 and 100. Where to put that condition?
Nowhere, I'd say. PERCENTAGE's data type, a numeric having precision 4 and scale 2 will take care about it.
As you didn't provide whole code you use, here's an example.
SQL> create or replace type pdv as object
2 (productid number,
3 name varchar2(30),
4 description varchar2(100),
5 percentage number(4, 2),
6 member function get_percentage return number
7 ) instantiable not final;
8 /
Type created.
SQL> create or replace type body pdv as
2 member function get_percentage return number as
3 begin
4 return self.percentage;
5 end get_percentage;
6 end;
7 /
Type body created.
SQL> create table product (prod pdv);
Table created.
SQL> insert into product values (pdv(1, 'Table', 'Made of oak', 20));
1 row created.
SQL> insert into product values (pdv(1, 'Table', 'Made of oak', 130));
insert into product values (pdv(1, 'Table', 'Made of oak', 130))
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
SQL> insert into product values (pdv(1, 'Table', 'Made of oak', 55.567));
1 row created.
SQL>
[EDIT, written after reading OP's comment]
I'm not sure I understood what you mean. If it means that you want to create an inline CHECK constraint, well, that won't work:
SQL> create or replace type pdv_typ as object
2 (
3 producid number,
4 name varchar2 (30),
5 description varchar2 (100),
6 percentage number (4, 2) constraint ch_perc check (percentage between 0 and 100),
7 member function get_percentage
8 return number
9 );
10 /
create or replace type pdv_typ as object
*
ERROR at line 1:
ORA-06545: PL/SQL: compilation error - compilation aborted
ORA-06550: line 6, column 29:
PLS-00103: Encountered the symbol "CONSTRAINT" when expecting one of the
following:
:= ) , not null default external character
ORA-06550: line 0, column 0:
PLS-00565: PDV_TYP must be completed as a potential REF target (object type)
SQL>
What you could do is to create a table whose column data type is of a previously created type, such as this:
SQL> create or replace type pdv_typ as object
2 (
3 producid number,
4 name varchar2 (30),
5 description varchar2 (100),
6 percentage number (4, 2),
7 member function get_percentage
8 return number
9 );
10 /
Type created.
SQL> create or replace type body pdv_typ
2 as
3 member function get_percentage
4 return number
5 as
6 begin
7 return self.percentage;
8 end get_percentage;
9 end;
10 /
Type body created.
SQL> create table pdv_tab
2 (
3 id number primary key,
4 pdv pdv_typ constraint ch_perc check (pdv.percentage between 0 and 100)
5 );
Table created.
SQL>
SQL> insert into pdv_tab values (1, pdv_typ (1, 'Table', 'Made of oak', 20));
1 row created.
SQL> insert into pdv_tab values (2, pdv_typ (2, 'Chair', 'Made of steel', 120));
insert into pdv_tab values (2, pdv_typ (2, 'Chair', 'Made of steel', 120))
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
SQL> insert into pdv_tab values (3, pdv_typ (3, 'Window', 'Made of glass', -5));
insert into pdv_tab values (3, pdv_typ (3, 'Window', 'Made of glass', -5))
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_PERC) violated
SQL>
Personally, I really, really don't like object side of Oracle. For me, it is a relational DBMS. Object support came as if they wanted to say hey, look, we can do that too!. I can't remember whether I ever used that functionality, except for educational purposes. Drawbacks? Plenty. Benefits? None. Once again, from my point of view.
So, what are you, really, doing? This is not a real-life problem, is it? That suggests your comment, saying that it has to be done that way. Says who? If it is a client, tell him to mind his own business. If it is a professor, then do what he says, regardless.
The straightforward way to do this would be a CHECK constraint on the table. That could be as simple as:
create table Product (
productID number primary key
, name varchar2(30) not null
, description varchar2(128) not null
, percentage number check (percentage between 0 and 100)
);
Demo in SQL Fiddle.
I have created two TYPE objects to try out OOP processing in PL/SQL.
I tried to use my type o_customers in my INSERT statement, but I could not do it.
There is a Customers table. It has same columns as o_customers.
create or replace type o_customers as object (
id number,
name varchar2(40),
age number,
address o_addressC,
salary number
);
create or replace type o_addressC as object (
mahalle varchar(30),
apartman varchar(15),
ilce varchar(15),
apt_no number
);
declare
adres o_addressC;
musteri o_customers;
begin
adres := o_addressC('selami ali mah','çınar apt',' üsküdar',19);
musteri:= o_customers(10,'UĞUR SİNAN SAĞIROĞLU',26,adres,1000);
insert into customers values (musteri);
end;
" There is a customers table. it has same columns with o_customers"
In OOP it is not enough for objects to have the same structure to be compatible in a programming context: they must be the same type, or related to each other through inheritance.
So you need to create the table using that type:
SQL> create table customers of o_customers
2 /
Table created.
SQL> desc customers
Name Null? Type
---------------------- -------- -------------
ID NUMBER
NAME VARCHAR2(40)
AGE NUMBER
ADDRESS O_ADDRESSC
SALARY NUMBER
SQL>
Now your insert statement will work:
SQL> declare
2 adres o_addressC;
3 musteri o_customers;
4 begin
5 adres := o_addressC('selami ali mah','cınar apt','uskudar',19);
6 musteri:= o_customers(10,'UĞUR SİNAN SAĞIROĞLU',26,adres,1000);
7 insert into customers values(musteri);
8 end;
9 /
PL/SQL procedure successfully completed.
SQL> select * from customers;
ID NAME AGE
---------- ---------------------------------------- ----------
ADDRESS(MAHALLE, APARTMAN, ILCE, APT_NO)
------------------------------------------------------------------------------------------------------------------------------------------------------
SALARY
----------
10 UĞUR SİNAN SAĞIROĞLU 26
O_ADDRESSC('selami ali mah', 'c??nar apt', ' uskudar', 19)
1000
SQL>
Incidentally I had to make minor changes to the inserted values because the posted statement hurled
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 6
This is because your o_addressC type attributes are too small for strings with multi-byte characters.
Unless customers is an object table (create table customers of o_customers), you'll need to refer to the object's properties explicitly:
insert into customers
( id, name, age, address, salary)
values
( musteri.id, musteri.name, musteri.age, musteri.address, musteri.salary );
By the way, o_customer (no 's') would make more sense than o_customers for an object name.
I have two Oracle questions.
How can I set the primary key of a table when the table is made up of an object type? e.g.
CREATE TABLE object_names OF object_type
I have created a Varray type,
CREATE TYPE MULTI_TAG AS VARRAY(10) OF VARCHAR(10);
but when I try to do
SELECT p.tags.count FROM pg_photos p;
I get an invalid identifier error on the "count" part. p.tags is a MULTI_TAG, how can I get the number of elements in the MULTI_TAG?
First of all I wouldn't recommend storing data in Object tables. Objects are a great programmatic tool but querying Object tables leads to complicated SQL. I would advise storing your data in a standard relationnal model and using the objects in your procedures.
Now to answer your questions:
A primary key should be immutable, so most of the time an Object type is inappropriate for a primary key. You should define a surrogate key to reference your object.
You will have to convert the varray into a table to be able to query it from SQL
For example:
SQL> CREATE TYPE MULTI_TAG AS VARRAY(10) OF VARCHAR(10);
2 /
Type created
SQL> CREATE TABLE pg_photos (ID number, tags multi_tag);
Table created
SQL> INSERT INTO pg_photos VALUES (1, multi_tag('a','b','c'));
1 row inserted
SQL> INSERT INTO pg_photos VALUES (2, multi_tag('e','f','g'));
1 row inserted
SQL> SELECT p.id, COUNT(*)
2 FROM pg_photos p
3 CROSS JOIN TABLE(p.tags)
4 GROUP BY p.id;
ID COUNT(*)
---------- ----------
1 3
2 3
1)
A primary key is a constraint, to add constrains on object tables check this link:
http://download-west.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjdes.htm#i452285
2)
The COUNT method can't be used in a SQL statement:
REF LINK IN COMMENTS
So in my case I had to do
SELECT p.pid AS pid, count(*) AS num_tags FROM pg_photos p, TABLE(p.tags) t2 GROUP BY p.pid;
Can someone explain what nested table objects are in Oracle ? While building an interface between to systems I discovered what was to me an odd column SYS_NC00054$. After some research I discovered that it was a nested table object from the function based index I created.
Function-based indexes are different from nested tables.
A regular index is built against actual columns ...
create index emp_job_idx on emp (job)
/
... whereas a function-based index is build on functions applied to columns. For instance we might what an index we can use when we query a date column without the time element...
create index emp_hire_idx on emp(trunc(hiredate))
/
When we query USER_IND_COLUMNS, the indexed column shows up in the first case but not in the second, because we are not indexing an actual column. What we see instead is the system generated "column'....
SQL> select index_name, column_name
2 from user_ind_columns
3 where table_name = 'EMP'
4 /
INDEX_NAME COLUMN_NAME
------------------------------ ---------------
PK_EMP EMPNO
EMP_UK ENAME
EMP_JOB_IDX JOB
EMP_HIRE_IDX SYS_NC00010$
SQL>
We can see the make-up of the index in USER_IND_EXPRESSIONS ...
SQL> select index_name, column_expression
2 from user_ind_expressions
3 where table_name = 'EMP'
4 /
INDEX_NAME COLUMN_EXPRESSION
------------------------------ --------------------
EMP_HIRE_IDC TRUNC("HIREDATE")
SQL>
Nested Tables
Nested tables are something different: they are user-defined arrays of simple or complex types. They can be used to define PL/SQL collections or columns in an ORDBMS table. Like this...
SQL> create or replace type address_t
2 as object
3 (
4 address_line_1 varchar2(70)
5 , address_line_2 varchar2(70)
6 , address_line_3 varchar2(70)
7 , address_line_4 varchar2(70)
8 , address_line_5 varchar2(70)
9 , postcode postcodestructure
10 ) final;
11 /
create or replace type address_t
*
ERROR at line 1:
ORA-02303: cannot drop or replace a type with type or table dependents
SQL>
SQL> create or replace type address_nt as table of address_t
2 /
Type created.
SQL>
SQL> create table contact_details (
2 person_id number not null
3 , email_address varchar2(254)
4 , addresses address_nt
5 )
6 nested table addresses store as nested_addresses
7 /
Table created.
SQL>
Basically, a table that has a column that stores data in the form of another table (or other complex type): A table nested inside another.
http://www.databasejournal.com/features/oracle/article.php/3788331/So-what-is-an-Oracle-Nested-Table.htm