Composite Keys: Foreign Keying and Primary Keying [duplicate] - sql

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.

Related

SQL Server: why are two foreign keys allowed on a column referencing to single column?

Why does SQL Server allow this?
create table dbo.tab1
(
id int primary key
)
create table dbo.tab2
(
id int constraint first_name references tab1(id),
constraint second_name foreign key (id) references tab1(id)
)
Here's an example that might clarify this a bit.
I have a person table which defines all of the people in the system. I then have a marriage table. A marriage is defined as a pairing of 1 Husband and 1 Wife, and both of these need to be valid entries in the Person table.
create table dbo.Person
(
id int primary key
)
create table dbo.Marriage
(
id int constraint Husband references tab1(id),
id2 int constraint Wife foreign key (id) references tab1(id)
)
Example was for clarity. Please forgive me for any political or cultural assumptions that may have gone into it.
Yes. This is quite interesting functionality wise. See if you are using parent child concept then it's helpful.
Example: If you have customer and dbo.Customer table. The customer distribute the commission after some recharge. So when you relate Customer to its parent chain you need the same column of customer table as foreign key twice.

Oracle SQL queries for subclass-table - Inheritance

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.

SQL constraint on a foreign 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.

Translating diagram to SQL Database

I'm having trouble seeing how I should translate this diagram into my database with tables. I'd like to add that I'm very new to this. This is a picture of an example that I want to translate into my SQL Database:
I'm not really sure how a diagram like this could look in my SQL Database, haven't really worked with inheritance. Would really appreciate if someone could demostrate how this could look with tables in SQL.
Thanks.
EDIT:
create table Person(
IDCode CHAR(10) UNIQUE NOT NULL,
primary key (IDCode),
);
create table Student(
IDCode CHAR(10) UNIQUE NOT NULL,
Name VARCHAR(15),
Course VARCHAR(15)
primary key (Name),
foreign key (IDCode) references Person (IDCode)
);
create table Teacher(
IDCode CHAR(10) UNIQUE NOT NULL,
Name VARCHAR(15),
Course VARCHAR(15)
primary key (Name),
foreign key (IDCode) references Person (IDCode)
);
create table StudentTeacherRelationship(
StudentName VARCHAR(15),
TeacherName VARCHAR(15),
primary key(StudentName,TeacherName),
foreign key(StudentName) references Student (Name),
foreign key(TeacherName) references Teacher (Name),
It means:
a person has a id number
both students and teachers are persons and they have their id information in person table, and one student/teacher has only one id
a student can have many teachers
a teacher can teach to many students
so there should be 4 tables(just psudo pseudo code to give you an idea):
person table:
id_person, (the primary key)
real_id (the real id, can be anything)
student table:
id_student,
id_person,
name,
other_stuff
teacher table:
id_teacher
id_person,
name,
other_stuff
a techer_student table (which make it many to many)
id_student
id_teacher
There are several ways to deal with inheritance situation in databases, JPA, for example, defines 3 strategies for inheritance in databases, these are: Single Table, Table for Class and Joined, they are all best described (including table/class examples) in the following link

Enforce constraints between tables

How do you establish a constraint where, one column (not the primary key) has to have the same value as another table's column. I'm not quite sure how to phrase it so here's an example:
Ex:
I have three tables, Employee, Director, Division and Department
The structure for the tables are as follows:
Employee
Id
Name
DirectorId (FK)
DepartmentID (FK)
Director
Id
Name
DepartmentID (FK)
Department
Id
Name
DivisionId (FK)
Division
Id
Name
Employees and directors both have departments, each department has a division but their divisions have to be the same. Is there a way to enforce this? (Hopefully without having to resort to triggers)
Create stored procedures that will have proper GRANTS and don't allow user to INSERT into table directly. Use stored procedures as interface to the database, and check required conditions in them before insertion.
First, your example tables are doing too much. There is a design principle that states that a single table should model an entity or a relationship between entities but not both. The relationships between departments, directors and employees (I'm assuming that directors are not employees; I'm also omitting divisions for the moment).
Second, a table can have more than one key, known as candidate keys. Further, you can create a UNIQUE constraint by 'appending' a non-unique column to a key. For example, employees' names do not make for a good key, hence the reason for having an employee ID (I don't think the same can be said for departments i.e. department name in itself is a good enough key). If employee_ID is unique then it follows that (employee_name, employee_ID) will also be unique.
Third, a table can be referenced by any UNIQUE constraint, it doesn't have to be the table's 'primary' key (which partly explains why 'primary key' is a bit of a nonsense).
The great thing about the above is that one can model the required constraints using FOREIGN KEY and row-level CHECK constraints. SQL optimizers and programmers prefer declarative solutions to procedural code (triggers, stored procs, etc). This vanilla SQL DDL will port to most SQL products.
So, the department name can be combined with both the director key and the employee key respectively and these compound keys can be referencesd in a simple two-tier org chart table: because both the employee's department and their director's department will appear in the same table, a simple row-level CHECK constraint can be used to test that they are the same e.g.
Entity tables:
CREATE TABLE Departments
(
department_name VARCHAR(30) NOT NULL UNIQUE
);
CREATE TABLE Employees
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_name VARCHAR(100) NOT NULL
);
CREATE TABLE Directors
(
director_ID INTEGER NOT NULL UNIQUE,
director_name VARCHAR(100) NOT NULL
);
Relationship tables:
CREATE TABLE EmployeeDepartments
(
employee_ID INTEGER NOT NULL UNIQUE
REFERENCES Employees (employee_ID),
employee_department_name VARCHAR(30) NOT NULL
REFERENCES Departments (department_name),
UNIQUE (employee_department_name, employee_ID)
);
CREATE TABLE DirectorDepartments
(
director_ID INTEGER NOT NULL UNIQUE
REFERENCES Directors (director_ID),
director_department_name VARCHAR(30) NOT NULL
REFERENCES Departments (department_name),
UNIQUE (director_department_name, director_ID)
);
CREATE TABLE OrgChart
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_department_name VARCHAR(30) NOT NULL,
FOREIGN KEY (employee_department_name, employee_ID)
REFERENCES EmployeeDepartments
(employee_department_name, employee_ID),
director_ID INTEGER NOT NULL,
director_department_name VARCHAR(30) NOT NULL,
FOREIGN KEY (director_department_name, director_ID)
REFERENCES DirectorDepartments
(director_department_name, director_ID),
CHECK (employee_department_name = director_department_name)
);
Now a slightly more interesting scenario would be when a director is assigned a division, rather than a specific department, and you had to test that the employee's department was in the same division as her director:
Entity tables:
CREATE TABLE Divisions
(
division_name VARCHAR(20) NOT NULL UNIQUE
);
CREATE TABLE Departments
(
department_name VARCHAR(30) NOT NULL UNIQUE,
division_name VARCHAR(20) NOT NULL
REFERENCES Divisions (division_name),
UNIQUE (division_name, department_name)
);
CREATE TABLE Employees
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_name VARCHAR(100) NOT NULL
);
CREATE TABLE Directors
(
director_ID INTEGER NOT NULL UNIQUE,
director_name VARCHAR(100) NOT NULL
);
Relationship tables:
CREATE TABLE EmployeeDepartments
(
employee_ID INTEGER NOT NULL UNIQUE
REFERENCES Employees (employee_ID),
employee_department_name VARCHAR(30) NOT NULL
REFERENCES Departments (department_name),
UNIQUE (employee_department_name, employee_ID)
);
CREATE TABLE DirectorDivisions
(
director_ID INTEGER NOT NULL UNIQUE
REFERENCES directors (director_ID),
director_division_name VARCHAR(20) NOT NULL
REFERENCES divisions (division_name),
UNIQUE (director_division_name, director_ID)
);
CREATE TABLE OrgChart
(
employee_ID INTEGER NOT NULL UNIQUE,
employee_department_name VARCHAR(30) NOT NULL,
FOREIGN KEY (employee_department_name, employee_ID)
REFERENCES EmployeeDepartments
(employee_department_name, employee_ID),
employee_division_name VARCHAR(20) NOT NULL
REFERENCES divisions (division_name),
FOREIGN KEY (employee_division_name, employee_department_name)
REFERENCES Departments (division_name, department_name),
director_ID INTEGER NOT NULL,
director_division_name VARCHAR(20) NOT NULL,
FOREIGN KEY (director_division_name, director_ID)
REFERENCES DirectorDivisions
(director_division_name, director_ID),
CHECK (employee_division_name = director_division_name)
);
There is no limitation on creating foreign keys--there's nothing to stop you from defining a foreign key constraint on these tables:
EMPLOYEE
DIRECTOR
...associating them to the DEPARTMENT table. Though frankly, I don't see the need for a DIRECTOR table--that should be either a boolean indicator in the EMPLOYEE table, or possibly an EMPLOYEE_TYPE_CODE with it's own foreign key constraint to distinguish between employees and directors.
Multiple Foreign Keys
The presence of a foreign key also doesn't stop you from putting a second (or third, etc) constraint on the same column. Consider the scenario of TABLE_C.column having foreign key constraints to both TABLE_A.col and TABLE_B.col -- this is perfectly acceptable in the database, but it means that only values that exist in both TABLE_A.col and TABLE_B.col can exist in the TABLE_C.column. IE:
TABLE_A
col
----
a
b
c
TABLE_B
col
----
c
Based on this example data, TABLE_C.column could only ever allow "c" as value to exist in the column if someone added two foreign key constraints to the TABLE_C.column, referencing TABLE_A.col and TABLE_B.col.