I have a Staff table with staffNo as the primary key
and staff details present in two other tables inheriting from it: FTLecturer and PTLecturer. I used the Optional Or relationship there.
My question is: how to write Oracle SQL queries for these sub-classes?
I think I do not need a PK for them again because they inherit from `Staff'. Is it so?
This is the Staff table
CREATE TABLE Staff
(staffNo number(10) NOT NULL,
firstName varchar2(50) NOT NULL,
lastName number(2) ,
address varchar2(50) NOT NULL,
CONSTRAINT courseID_pk PRIMARY KEY (staffNo),
CONSTRAINT fk_Module
FOREIGN KEY (moduleID)
REFERENCES Module(Module Module ID)
);
I need to create the FTLecturer table with the Optional Or relationship.
Inheritance is a concept from Object-Oriented Programming: it has no meaning in relational databases. The most important impact of this is that child tables do need a primary key.
"I need to create the FTLecturer table with the Optional Or relationship."
What you're describing is called an Arc in relational databases: a lecturer can be full-time or part-time but not both. We can enforce this with a decent set of constraints.
First add a column to the parent table to identify the Lecturer type.
alter table staff add staffType varchar2(10);
This should be validated with a foreign key against a reference data table, and at a pinch a check constraint. Then we add a unique constraint (yes, as well as a primary key):
alter table staff add constraint staff_uk unique(staffNo, staffType);
We can use this to enforce the arc on the child tables.
create table FTLecturer (
staffNo number not null,
staffType varchar2(10) not null,
tenure varchar2(3) not null,
constraint FTLecturer_pk primary key (staffNo),
constraint FTLecturer_ck check (staffType = 'FTL'),
constraint FTLecturer_Staff_fk foreign key (staffNo, staffType)
references staff (staffNo, staffType);
Note that the foreign key means we can only insert rows in this table which have a parent of the correct type in the STAFF table. This is why we need the StaffType column and that unique constraint on the STAFF table.
Likewise for Part-Time Lecturers:
create table PTLecturer (
staffNo number not null,
staffType varchar2(10) not null,
hours number not null,
constraint PTLecturer_pk primary key (staffNo),
constraint PTLecturer_ck check (staffType = 'PTL'),
constraint PTLecturer_Staff_fk foreign key (staffNo, staffType)
references staff (staffNo, staffType);
Since Oracle 11g we can use a virtual column to apply a constant value for the staffType on the child tables. This avoids the need for the check constraints. Find out more.
To create a record for a specific member of staff it is good practice to populate the parent and child in the same action; we can use the INSERT ALL syntax to populate multiple tables. Find out more.
Finally, you can build a helpful API with views. For instance:
create or replace view fulltimeLecturer as
select staff.*
, ftl.tenure
from staff
join ftlecturer ftl
on staff.staffno = ftl.staffno
and staff.stafftype = ftl.stafftype;
create or replace view parttimeLecturer as
select staff.*
, ptl.hours
from staff
join ptlecturer ptl
on staff.staffno = ptl.staffno
and staff.stafftype = ptl.stafftype;
This may strike you as a lot of work, and inflexible to boot. Here is the difference between Object Programming and Relational Databases. OOP is primarily driven by helping developers to write code; RDBMS is focused on guaranteeing the integrity of the stored data.
Related
This question already has answers here:
Foreign key relationship with composite primary keys in SQL Server 2005
(3 answers)
Closed 2 years ago.
I am now working on a new exercise and have been given the whole ERD, just have to make the database and do some queries. A note was given that Rates table has a Composite Primary Key. I know how to make Composite Primary Keys
CONSTRAINT [name] PRIMARY KEY ([Col1],[Col2]) Col1 is an Int, Col2 is a Varchar
This table is then foreign keyed into the main table. To my knowledge there is no way to do this. Does anyone happen to know if there is a way?
Here is an example for composite keys. The database contains companies identified by some code for instance the EIN in the USA. The companies have departments and each company can decide for unique codes to identify their departments. Company A may use BD for their buying department, while company B uses BD also, but for their base department. Then each company has employees and each company uses some employee number to identify them. Employee #123 in comapny A is another person than employee #123 in company B. One employee works in one department in one company.
create table company
(
company_no decimal(9,0),
company_name varchar(100),
primary key (company_no)
);
create table department
(
company_no decimal(9,0),
department_code varchar(20),
name varchar(100),
primary key (company_no, department_code),
foreign key(company_no) references company(company_no)
);
create table employee
(
company_no decimal(9,0),
employee_no decimal(9,0),
first_name varchar(50),
last_name varchar(50),
department_code varchar(20),
primary key (company_no, employee_no),
foreign key(company_no, department_code) references department(company_no, department_code)
);
We could also add a constraint
foreign key(company_no) references company(company_no)
to the employee table, but that would be superfluous, as we already have the constraint on a department belonging to a company.
Is it possible to check the value of an attribute in a different table in table creation? For example I have this table ticket:
CREATE TABLE ticket
(
id_ticket_pk NUMBER(4) PRIMARY KEY,
hand_in_date DATE NOT NULL,
num_clothes NUMBER(4) NOT NULL,
deposite NUMBER (8,2) NOT NULL,
comment VARCHAR2(40),
tax NUMBER(5,3) NOT NULL,
status VARCHAR2(15) NOT NULL,
id_counter_fk1 NUMBER(4),
id_client_fk2 NUMBER(4),
CONSTRAINT ticket_id_counter_fk1
FOREIGN KEY (id_counter_fk1) REFERENCES empleado(id_employee_pk),
CONSTRAINT ticket_id_client_fk2
FOREIGN KEY(id_client_fk2) REFERENCES client(id_client_pk)
);
This table relates to the employee table which has an attribute called type that can be equal to C - for counter, S- for secretary etc... I would like to know if its possible to add a constraint in the creation of the table that verifies that the employee inserted has an employee.type = 'C' where employe.id_pk = ticket.id_counter_fk2. Or do I have to create an external function or client App that manages this?
You seem to be asking whether you can use the foreign keying mechanism to ensure that only people with the job title of "counter" can create support tickets.
The short answer is no, you can't have a foreign key on this table that checks the employee table pk for the value given in id_counter_fk1 and enforces that the employee type be C
You could do it several other ways, the most direct being a trigger that prevents the insert if the employee linked is not a C type, but the FK mechanism exists to ensure that a remote record exists or not, not that it exists and has particular properties
This is what I am trying to create:
CREATE TABLE VEHICLEREPORT
(
DeptID char(2) not null,
Vin# char(3) not null,
Miles varchar(6) not null,
Bill# char(3) not null,
EID char(3) not null,
PRIMARY KEY (DeptID, Vin#),
FOREIGN KEY (bill#) REFERENCES billing,
FOREIGN KEY (EID) REFERENCES Employee
);
The issue is with my reference to billing. The error says:
The number of columns in the referencing column list for foreign key 'FK__VEHICLERE__Bill#__5AEE82B9' does not match those of the primary key in the referenced table 'Billing'.
but my billing table entered fine:
CREATE TABLE BILLING
(
VIN# char(3),
BILL# char(3),
PRIMARY KEY (VIN#, Bill#),
FOREIGN KEY (VIN#) REFERENCES vehicle
);
What am i missing with this?
Appreciate the help.
If you think of the foreign key as establishing a parent-child relationship between two tables, then the parent side column(s) need to be unique.
From Wikipedia:
In the context of relational databases, a foreign key is a field (or collection of fields) in one table that uniquely identifies a row of another table or the same table. ... In simpler words, the foreign key is defined in a second table, but it refers to the primary key or a unique key in the first table.
In your example, there is no guarantee that VIN# is unique in VEHICLEREPORT. Below are your options
VIN# is guaranteed to be unique in VEHICLEREPORT. In this case add a UNIQUE constraint on VIN# on the VEHICLEREPORT table. The error will go away.
VIN# is not unique in VEHICLEREPORT (doesn't seem likely). If this is the case, then likely there is a flaw in the design of your BILLING table as it could likely point to more than one row in VEHICLEREPORT. You should consider adding DeptID column to BILLING and creating a composite foreign key.
Also if VIN# is unique (case 1 above), you should think of why DeptID is present in the PK. Maybe the right fix at the end is to drop DeptID from the primary key.
I am having problems creating a constraint for a foreign key field, so that a foreign key can only be entered if that foreign key links to a row containing a specific attribute.
To give a better idea about what I mean, I have created the following example. The Employee entity table contains a Grade field, which can either be 'S' for a senior level employee, or 'J' for a junior level employee. In the Expenses table, I want to limit any entries into the ApprovedBy field to those EmpNo values that have a Grade field containing 'S' in the Employee table.
CREATE TABLE Employee
(EmpNo INT PRIMARY KEY,
FirstName VARCHAR(15),
LastName VARCHAR(15),
Grade CHAR(1),
CONSTRAINT chk_ValidGrade CHECK (Grade IN ('J','S'))
)
CREATE TABLE Expenses
(ExpenseId INT IDENTITY(1,1) PRIMARY KEY,
Amount FLOAT,
ApprovedBy INT FOREIGN KEY REFERENCES Employee(EmpNo),
)
I instinctively want to use a join, or other relational algebra function to do this. However, my understanding is that you can't use the SELECT function within a CHECK function, so I'm not sure how I would define the constraint.
As far as I know, you cannot use check constraint for this task. You have to use a trigger for insert and update in your Expenses table.
let's say i have 2 tables:
Department(depNum)
Worker(id,deptNum) - key should be id
now i want dept to reference an existing value in Department.
so i write in create table:
CREATE TABLE Worker(
id integer primary key,
dept integer references Department);
my question is, i've seen in many examples that you also put foreign key with the references statement. i don't understand what is primary key for.
does it mean that dept will be also a key on Worker?
thank you
From Wikipedia:
A primary key is a combination of columns which uniquely specify a
row. It is a special case of unique keys. . . . Primary keys were
added to the SQL standard mainly as a convenience to the application
programmer.
You cannot reference a record in a table without a primary key. A foreign key lets you reference a record in another table within an individual record. This foreign key is usually referencing the primary key in the foreign table.
This post has a lot of great information. In particular, check out the highest ranked answer for a bullet list of do's and do not's.
What's wrong with foreign keys?
This post gives a pretty decent explanation, given the poster's
original example:
What will these foreign keys do?
Let's say that each worker can only work in one department at any one time.
So each department has its own unique ID. This is the department's primary key because two departments should never have the same id.
Now, each individual worker must be tracked so they are also assigned their own unique ID. This is their primary key. You need to link the worker to the department that they work in and since they can only work in one department at a time, you can have their department as a foreign key. The foreign key in the worker table is linked to the ID of the department table.
This has more information: http://www.1keydata.com/sql/sql-foreign-key.html
You have two tables:
PLAYER,
primary key (unique) PK_player_id
player_name
foreignt key to TEAM.team_id FK_team_id
TEAM
primary key (unique) PK_team_id
team_name
Every PLAYER is in exact one TEAM.
The PLAYER has a FOREIGN-KEY to the TEAM (FK_team_id). Also you can delete the TEAM, which will delete all player in it cascading (if configured).
Now you can't create a player without an existing TEAM, because the database ensures this.
EDIT:
Didn't you ask for the foreign key?
The primary key is one or more than one column, which will identify on datarow within your database. If jou want to create a foreign key, you have to use a column or more than one column) which is unique.
In my example, there is a unique key (the primary key) for every table, because the name may change. To identify the 'target' of the foreign key, it has to be unique. so it is liklye to use the prmary key of the second table. (TEAM.PK_team_id)
I am not clear, the requirement should be
Department(dept)
Worker(id,dept) - key should be id
which means dept is the primary key in Department and foreign key in worker.
the foreign key is not unique in worker table but it is unique in Department Table.
The worker table cannot have some unknown department which is not defined in the Department.
Did I make sense ?
To ensure the integrity of the tables, not allowing you to enter values in the table (Worker) without referencing an existing row (at Department)
According to the SQL-92 Standard:
A foreign key (FK) may reference either a PRIMARY KEY or a UNIQUE CONSTRAINT. In the case of a PRIMARY KEY, the referenced columns may be omitted from the foreign key declaration e.g. the following three are all valid:
CREATE TABLE Department ( Department INTEGER NOT NULL PRIMARY KEY, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department, ...);
CREATE TABLE Department ( Department INTEGER NOT NULL PRIMARY KEY, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department (dept), ...);
CREATE TABLE Department ( Department INTEGER NOT NULL UNIQUE, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department (dept), ...);
The following is not valid:
CREATE TABLE Department ( Department INTEGER NOT NULL UNIQUE, ...);
CREATE TABLE Worker (dept INTEGER REFERENCES Department, ...);
...because the referenced columns involved in the foreign key must be declared.
When declaring a simple (single-column) FK in-line the FOREIGN KEY keywords are omitted as above.
A composite (multiple-column) cannot be declared in-line and a simple FK need not be declared in-line: in these cases, the referencing column(s) AND the FOREIGN KEY keywords are required (the rules for the referenced columns remain the same as stated earlier) e.g. here are just a few examples:
CREATE TABLE Department ( Department INTEGER NOT NULL PRIMARY KEY, ...);
CREATE TABLE Worker (dept INTEGER, FOREIGN KEY (dept) REFERENCES Department, ...);
CREATE TABLE Department ( Department INTEGER NOT NULL UNIQUE, ...);
CREATE TABLE Worker (dept INTEGER, FOREIGN KEY (dept) REFERENCES Department (dept), ...);
CREATE TABLE DepartmentHistory
(
dept INTEGER NOT NULL,
dt DATE NOT NULL,
PRIMARY KEY (dt, dept),
...
);
CREATE TABLE Worker
(
dept INTEGER NOT NULL,
dept_dt DATE NOT NULL,
FOREIGN KEY (dept_dt, dept) REFERENCES DepartmentHistory,
...
);