Oracle SQL : Data won't get inserted into super table - sql

I am trying to create two classes, Persons and Customers. Customers being the subclass of Persons. When I try to insert values into Customers table, although I can see the value inserted in the customers table, I don't understand why it wouldn't get inserted into Persons table also as it is a superclass of customers. Is there a way I can insert into subclass through superclass or vice versa? Here is my code
CREATE TYPE PersonType AS OBJECT (
PID VARCHAR2(5),
Name VARCHAR2(30),
Address VARCHAR2(35),
age NUMBER(3)
) NOT FINAL;
/
CREATE TABLE Person of PersonType;
/
CREATE TYPE CustomerType UNDER PersonType (
CID VARCHAR2(20));
/
CREATE TABLE Customer of CustomerType;
/
INSERT INTO Customer VALUES(CustomerType('P2','Andy','Poland',21,'SS','C9'));
/
SELECT * FROM Person;

When you insert a row in an object table, it only goes in that table. Even if it's a subtype.
If you want the data in both person and customer, you need two inserts. But then you're duplicating the customer attributes!
When you have a type hierarchy, you can create an object table on the parent object. And insert subtypes into that. You only need to create a separate customer table if you want to only insert CustomerType objects into it.
If you insert all objects in the person table, you can pull out rows of a specific subtype with the is of (<objecttype>)' condition:
CREATE TYPE PersonType AS OBJECT (
PID VARCHAR2(5),
Name VARCHAR2(30),
Address VARCHAR2(35),
age NUMBER(3)
) NOT FINAL;
/
CREATE TYPE CustomerType UNDER PersonType (
CID VARCHAR2(20));
/
INSERT INTO Person VALUES(CustomerType('P2','Andy','Poland',21,'SS'));
INSERT INTO Person VALUES(PersonType('P3','Chris','Poland',21));
select * from person p;
PID NAME ADDRESS AGE
P2 Andy Poland 21
P3 Chris Poland 21
select * from person p
where value ( p ) is of ( CustomerType );
PID NAME ADDRESS AGE
P2 Andy Poland 21
But to be honest, you're better off storing the data using regular relational tables:
create table person (
pid varchar2(5)
primary key,
name varchar2(30),
address varchar2(35),
age number(3)
);
create table customer (
pid
references person ( pid )
not null,
cid varchar2(20)
);

Related

Copy oracle table data from two tables to another table

Here are my tables:
create table country(
country_id number(5) primary key,
country varchar2(36)
);
create table city(
city_id number(5) primary key,
country_id number(5) constraint city_country_fk references country(country_id) NOT NULL,
city varchar2(36)
);
SQL> desc airportdemodata;
Name Null? Type
----------------------------------------- -------- ----------------------------
AIRPORT_ID NOT NULL NUMBER(5)
IATA_CODE VARCHAR2(3)
CITY VARCHAR2(36)
COUNTRY VARCHAR2(36)
AIRPORT VARCHAR2(58)
I inserted countries from airportdemodata to country table as under:
INSERT INTO country (country)
SELECT unique(country) from airportdemodata;
it worked fine.
Now I am trying to copy airportdemodata.city into city.city(country_id,city) by matching airportdemodata.country with country.country. I tried like this:
SQL> SELECT a.unique(city), b.country_id FROM airportdemodata a, country b where a.country=b.country;
SELECT a.unique(city), b.country_id FROM airportdemodata a, country b where a.country=b.country
*
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
Right; inventing your own syntax usually leads to the outcome you experienced. Did you mean to use distinct?
SELECT DISTINCT a.city,
b.country_id
FROM airportdemodata a
JOIN country b ON a.country = b.country;

How can I insert values from a nested table into another table?

I want to grab values from a nested table in one table and insert said values into another table
Here's the type for the nested table:
CREATE OR REPLACE TYPE type_val AS OBJECT
(
year DATE,
amount INTEGER
);
The nested table:
CREATE OR REPLACE TYPE nt_type_val IS
TABLE OF type_val;
Here's the table that contains the nested table:
CREATE TABLE country
(
id INTEGER NOT NULL,
name VARCHAR2(100) NOT NULL,
continent VARCHAR2(30) NOT NULL,
prod_an nt_type_val
)
NESTED TABLE prod_an STORE AS nt_prod_an;
Here's the table into which I want to insert
CREATE TABLE prod_country_ai
(
year DATE NOT NULL,
amount INTEGER NOT NULL,
country_fk INTEGER NOT NULL
)
What I want to do is I want to grab the values from prod_an in the country table for each country and store them in the prod_country_ai table, respectively, year and amount from the nested table (prod_an) into year and amount on prod_country_ai and the primary key from country into country_fk on prod_country_ai.
I have the following piece for a procedure that would do that:
DECLARE
CURSOR inner_table IS
SELECT t.* FROM country p, TABLE(p.prod_an) t
WHERE p.name = 'Portugal';
BEGIN
FOR i IN inner_table LOOP
dbms_output.put_line( i.year || i.quantity);
END LOOP;
END;
This successfully outputs the year followed by the amount but it only does so upon specification of the country name, the solution I thought of is running an "outer loop" that cycles on the country table (could be by id or by country name it doesn't change much because each value will be unique either way), and I'm guessing I can use i.year and i.quantity directly on an insert statement inside the "inner loop" to insert into prod_country_ai, but I'm not sure how I can do this, also, I think variables are treated as "local" inside a loop so how could I go about inserting the country primary key as a foreign key in the prod_country_ai table?
You don't need a procedure for this. You can do this with an INSERT ... SELECT from the countries cross joining the nested tables.
INSERT INTO prod_country_ai (year, amount, country_fk)
SELECT
p.year, p.amount, c.id
FROM
country c
CROSS JOIN TABLE(c.prod_an) p;

How to extract data from two tables using SQL object relational statement in oracle 11g

I am trying to solve the following query using object relational approach but don't know what is the proper way.
Find the number of saving accounts at each branch, displaying the
number and branch’s address.
I created two tables and insert some data like this:
--THIS IS BRANCH TABLE:
create type Branch_Address as object(
street varchar2(20),
city varchar2(20),
p_code varchar2(10))
not final
/
create type Branch_Phone as object(
phone varchar2(20))
not final;
/
create type branch_type as object(
bID varchar2(10),
bAddress Branch_Address,
bPhone Branch_Phone)
/
create table branch of branch_type(
primary key (bID))
/
insert into branch values(
'901',Branch_Address('Nic Street','Jordan','ABH887A'),Branch_Phone('0335454888'));
/
insert into branch values(
'906',Branch_Address('East End Garden','California','L181QP'),Branch_Phone('07455668711'));
/
insert into branch values(
'912',Branch_Address('Fredrick Street','London','LA112AS'),Branch_Phone('02841124478'));
/
insert into branch values(
'924',Branch_Address('West Street','Cambridge','CA8L871'),Branch_Phone('04511477885'));
--This is account table
create type account_type as object(
accNum int,
accType varchar2(15),
balance number,
bID ref branch_type,
inRate number,
limitOfFreeOD number,
openDate DATE)
/
create table account_table of account_type(
primary key (accNum))
/
insert into account_table
select account_type('1001','current','820.50',ref(b),'0.005','800','01-May-11')
from branch b
where b.bID = '901';
/
insert into account_table
select account_type('1010','saving','2155',ref(b),'0.02','0','08-Mar-10')
from branch b
where b.BID = '906';
/
insert into account_table
select account_type('1002','current','2600',ref(b),'0.005','1000','10-Apr-13')
from branch b
where b.BID = '912';
/
insert into account_table
select account_type('1112','saving','24000',ref(b),'0','1700','16-Jun-16')
from branch b
where b.BID = '924';
/
Branch(bID, street, city, p_code, bPhone)
Account(accNum, accType, balance, bID, inRate, limitOfFreeOD, openDate)
Bold is primary key
Italic is foreign key (In object relational we don't use Join if I am right).
Any help? Thanks.
Here's how you can join those:
select b.bid,
(select count(1) from account_table a
where a.bid.bid = b.bid
and a.acctype='saving'
) as num_accounts,
b.baddress.street, b.baddress.city, b.baddress.p_code
from branch b;
This is more confusing because branch_type.bID is a varchar2(10) and account_type.bID is a ref branch_type. I would rename bID on account_type to something like accBranch to be more clear that it does not store the ID, but is a reference to the entire object.
I haven't tested this query, but you can also write this as a join (below) instead of a subquery (above). They each have their uses.
select b.bid, count(1) as num_accounts,
b.baddress.street, b.baddress.city, b.baddress.p_code
from branch b
join account_table a
on a.bid.bid = b.bid
and a.acctype='saving'
group by b.bid, b.baddress.street, b.baddress.city, b.baddress.p_code;

SQL - foreign key one table with 3 owner tables

I have the following table Widget which is going to have an owner associated with each row.
The owner can be an id from User, Company or Department Tables. I'm guessing how to set this up is to make a link table like so?
id | user | company | department
---------|----------|----------|----------
1 | 4 | NULL | NULL
2 | 6 | 3 | 6
3 | 10 | 3 | 8
and then have the Widget table use that ID as the owner provided logic is in the app that if company is not null then the owner is the company otherwise owner would be user.
a department can't exist if there's no company.
It is not a problem if you want to add three foreign key (FK) columns from the three tables (USER, COMPANY, DEPARTMENT) respectively on the WIDGET table. You can distinguish real owner using JOIN operation described below;
CREATE TABLE WIDGET (
WIDGET_NAME VARCHAR(20),
OWNER_USER_ID INTEGER REFERENCES USER(ID),
OWNER_COMPANY_ID INTEGER REFERENCES COMPANY(ID),
OWNER_DEPART_ID INTEGER REFERENCES DEPARTMENT(ID),
);
-- retrieve OWNER_USER (you can JOIN with the USER table)
SELECT OWNER_USER_ID, WIDGET_NAME FROM WIDGET WHERE OWNER_COMPANY_ID IS NULL;
-- retrieve OWNER_COMPANY (plus OWNER_DEPART) (you can JOIN with the COMPANY and DEPARTMENT table)
SELECT OWNER_COMPANY_ID, OWNER_DEPART_ID, WIDGET_NAME FROM WIDGET WHERE OWNER_COMPANY_ID IS NOT NULL;
If you want to add just a single PK column from three tables, it doesn't make sense theoretically, but you can do it under some extra conditions. You said the owner of one widget in WIDGET table is a company if company is not null. But if company is null, then the owner is a user. If user (or corresponding identifier) column in WIDGET table is always not null whether company (or corresponding identifier) column is null or not, then you can just pick up the primary key (PK) column of USER table as a single FK of WIDGET table. Why? User → Company and User → Department dependencies are generated by this condition. It means, if you select a user A, then it is trivial that there is no more two companies related to him or her, and same as between user and department.
-- Schema of USER, COMPANY, DEPARTMENT table
CREATE TABLE USER (
ID INTEGER PRIMARY KEY,
NAME VARCHAR(20),
COMPANY_ID INTEGER REFERENCES COMPANY(ID),
DEPART_ID INTEGER REFERENCES DEPARTMENT(ID)
);
CREATE TABLE COMPANY (
ID INTEGER PRIMARY KEY,
NAME VARCHAR(20)
);
CREATE TABLE DEPARTMENT (
ID INTEGER PRIMARY KEY,
NAME VARCHAR(20)
);
-- Schema of WIDGET table
CREATE TABLE WIDGET (
WIDGET_NAME VARCHAR(20),
OWNER_ID INTEGER REFERENCES USER(ID)
);
-- retrieve OWNER_USER
SELECT U.NAME AS OWNER_USER_NAME, W.WIDGET_NAME
FROM WIDGET W, USER U
WHERE U.ID = W.OWNER_ID AND U.COMPANY_ID IS NULL;
-- retrieve OWNER_COMPANY
SELECT C.NAME AS OWNER_COMPANY_NAME, W.WIDGET_NAME
FROM WIDGET W, USER U, COMPANY C
WHERE U.ID = W.OWNER_ID AND U.COMPANY_ID = C.ID;
-- retrieve OWNER_DEPARTMENT
SELECT D.NAME AS OWNER_DEPART_NAME, W.WIDGET_NAME
FROM WIDGET W, USER U, DEPARTMENT D
WHERE U.ID = W.OWNER_ID AND U.COMPANY_ID IS NOT NULL AND U.DEPART_ID IS NOT NULL AND U.DEPART_ID = D.ID;
But if user column in WIDGET table can be null even though company column is not null, then you build up another OWNER table to keep your owner information (USER, COMPANY, DEPARTMENT). Of course, each record of WIDGET must be unique so composite unique index may be needed. (See http://www.postgresql.org/docs/current/static/indexes-unique.html)
-- Schema of OWNER table
CREATE TABLE OWNER (
ID INTEGER PRIMARY KEY.
OWNER_USER_ID INTEGER REFERENCES USER(ID),
OWNER_COMPANY_ID INTEGER REFERENCES COMPANY(ID),
OWNER_DEPARTMENT_ID INTEGER REFERENCES DEPARTMENT(ID)
);
-- unique index on OWNER
CREATE UNIQUE INDEX OWNER_UIDX ON OWNER( OWNER_USER_ID, OWNER_COMPANY_ID, OWNER_DEPARTMENT_ID );
-- Schema of WIDGET table
CREATE TABLE WIDGET (
WIDGET_NAME VARCHAR(20),
OWNER_ID INTEGER REFERENCES OWNER(ID)
);

SQL (not exists command)

create table class (cid integer primary key , cname text);
create table student (sid integer primary key, sname text);
create table attend ( cid integer , sid integer, grade integer);
Select A.cid, S.sname, S.sid
From Student S, Attend A
Where S.sid=A.sid and not exists
(Select *
From Attend A2
Where A2.cid=A.cid and A2.grade > A.grade);
I don't understand why the result is:
For each class id display the names of students that got the maximum grade in this class
I thought it would instead return the student with minimum grade for each class.
Could anyone help? Thanks!
Note the not operator there - this query select the student(s) that doesn't have any other student with a greater grade than him - i.e., he has the maximum grade.