Same primary keys for relation - sql

Lets say I have two many-to-many relations called Tutors and Assits. They are both connected courses. If they are both inheritance of relation called Staff they both have the same primary keys. That would mean the many-to-many relation will also have the same primary keys.
If I have two relations with the same primary keys what do I do? Here is an example of the table:

It should be pretty simple to add those two relationships. For example:
create table staff (
id int primary key not null,
name varchar(20)
);
create table tutor (
id int primary key not null,
office_number varchar(10),
foreign key (id) references staff (id)
);
create table assistant (
id int primary key not null,
title varchar(20),
foreign key (id) references staff (id)
);
create table course (
course_id int not null,
year int not null,
semester int not null,
primary key (course_id, year, semester),
tutor_id int not null references tutor (id),
assistant_id int not null references assistant (id)
);
Now, if you insert some data:
insert into staff (id, name) values (1, 'Alice');
insert into staff (id, name) values (2, 'Victor');
insert into tutor (id, office_number) values (1, '101-A');
insert into assistant (id, title) values (2, 'Adjunct Professor');
insert into course (course_id, year, semester, tutor_id, assistant_id)
values (101, 2020, 1, 1, 2);
You can run a query over it:
select
c.course_id, c.year, c.semester,
ts.name as tutor, t.office_number,
ta.name as assistant, a.title
from course c
join tutor t on c.tutor_id = t.id
join staff ts on ts.id = t.id
join assistant a on c.assistant_id = a.id
join staff ta on ta.id = a.id
Result:
course_id year semester tutor office_number assistant title
---------- ----- --------- ------ -------------- ---------- -----------------
101 2020 1 Alice 101-A Victor Adjunct Professor
See running example at DB Fiddle.

If the relation course - tutor is a many-to-many relation you will need an extra xref table:
course -|---|< course_tutor >0---|- tutor
The same thing for assistant.
Even when the same person is tutor and assistant in the same course there will be a record in course_tutor and course_assistant with the same course_id and staff_id but that is not a problem.

Related

Find all the persons which contains the provided resources

Below are the tables:
CREATE TABLE Person(
PersonID INT PRIMARY KEY,
FirstName VARCHAR(10),
LastName VARCHAR(10));
CREATE TABLE Resources(
ResourceID CHAR(3) PRIMARY KEY
);
CREATE TABLE PR (
PersonID INT,
ResourceID CHAR(3),
CONSTRAINT pkpr PRIMARY KEY (PersonID, ResourceID),
CONSTRAINT fkPersonID FOREIGN KEY (PersonID) REFERENCES Person(PersonID),
CONSTRAINT fkResourceID FOREIGN KEY (ResourceID) REFERENCES Resources(ResourceID));
INSERT INTO Person(PersonID, FirstName, LastName) VALUES (1, 'Bill', 'Smith'),(2, 'John','Jones');
INSERT INTO Resources (ResourceID) VALUES ('ABC'),('DEF'),('HIJ');
INSERT INTO PR (PersonID, ResourceID) VALUES (1,'ABC'),(1,'DEF'),(2,'ABC'), (2,'HIJ'), (1,'HIJ');
How to find all the persons which has resources ('ABC', 'DEF') ?
With above inserted data it should return person Bill Smith
I am using PostgreSql.
You can use aggregation:
select pr.personid
from pr
where pr.resourceid in ('ABC', 'DEF')
group by pr.personid
having count(*) = 2;
The primary key on pr prevents duplicates, so count(*) ensures that both resources are assigned to the person.

Counting in Oracle 11g

all day I am struggling with oracle exrcises and again I stuck. I need to select last names of boxers with their wins of each weight category.
So I have:
table "boxer" with columns: id, fname, lname, weight
table "fight" with two foreign keys from table boxer (id_boxer1 and id_boxer2) and with one column winner (if boxer1 won then winner will be number 1, if boxer2 won then winner will be number 2)
table "category_weight" with columns: id, min_weight, max_weight, name (of a category)
Example:
CREATE TABLE category_weight(
id INTEGER NOT NULL,
min_weight SMALLINT NOT NULL,
max_weight SMALLINT NOT NULL,
name VARCHAR2(20) NOT NULL
);
ALTER TABLE category_weight ADD CONSTRAINT category_weight_pk PRIMARY KEY ( id );
CREATE TABLE boxer(
id INTEGER NOT NULL,
fname VARCHAR2(20) NOT NULL,
lname VARCHAR2(20) NOT NULL,
weight INTEGER NOT NULL
);
ALTER TABLE boxer ADD CONSTRAINT boxer_pk PRIMARY KEY ( id );
CREATE TABLE fight(
id INTEGER NOT NULL,
winner SMALLINT NOT NULL,
id_category_weight INTEGER NOT NULL,
id_boxer1 INTEGER NOT NULL,
id_boxer2 INTEGER NOT NULL
);
ALTER TABLE fight ADD CONSTRAINT fight_pk PRIMARY KEY ( id );
ALTER TABLE fight
ADD CONSTRAINT boxer_fk FOREIGN KEY ( id_boxer1 )
REFERENCES boxer ( id );
ALTER TABLE fight
ADD CONSTRAINT boxer_fk2 FOREIGN KEY ( id_boxer2 )
REFERENCES boxer ( id );
ALTER TABLE fight
ADD CONSTRAINT categ_weight_fk FOREIGN KEY ( id_category_weight )
REFERENCES category_weight ( id );
INSERT INTO boxer
VALUES ('1', 'Johnny','Johnny','60');
INSERT INTO boxer
VALUES ('2', 'Anthonny','Anthonny','54');
INSERT INTO boxer
VALUES ('3', 'Anonimm','Anonimm','59');
INSERT INTO boxer
VALUES ('4', 'John','Johnowski','71');
INSERT INTO category_weight
VALUES ('1', '1','70','category1');
INSERT INTO category_weight
VALUES ('2', '71','100','category2');
INSERT INTO fight
VALUES ('1','1','1','1','2');
INSERT INTO fight
VALUES ('2','2','1','3','1');
Boxer with ID "1" won two fights in category1, so the result should be:
Lname Category Wins
Johnny category1 2
Here, try this:
SELECT b.lname,
cw.max_weight AS WEIGHT_CLASS,
COUNT(CASE WHEN f.winner = b.id THEN 1 ELSE NULL END) AS WINS
FROM boxer b
INNER JOIN fight f ON b.id = f.id_boxer1 OR b.id = f.id_boxer2
INNER JOIN category_weight cw ON f.id_category_weight = cw.id
GROUP BY b.lname, cw.max_weight

SQL - Subquery, SELECT from select

My database query :
CREATE DATABASE [College Assignment]
PRINT 'CREATE DATABASE College Assignment'
GO
USE [College Assignment]
CREATE TABLE Departments
(DEPART nvarchar(255) NOT NULL, D_NAME nvarchar(255), HEAD nvarchar(255),PRIMARY KEY (DEPART));
CREATE TABLE Courses
(COURSE_ID nvarchar(255) NOT NULL,
COURSE_NAME nvarchar(255),
"TYPE" nvarchar(255),
POINTS float,
DEPARTMENT_ID nvarchar(255),
PRIMARY KEY (COURSE_ID),
CONSTRAINT fk_dep
FOREIGN KEY (DEPARTMENT_ID) REFERENCES Departments(DEPART));
CREATE TABLE Students
(STUDENT_ID float NOT NULL,
S_NAME nvarchar(255),
CITY nvarchar(255),
PRIMARY KEY (STUDENT_ID));
CREATE TABLE Grades
(STUDENT_ID float NOT NULL,
COURSE_ID nvarchar(255) NOT NULL,
SEMESTER nvarchar(255),
TERM nvarchar(255),
GRADE smallint,
GRADE_SEM smallint,
PRIMARY KEY (STUDENT_ID, COURSE_ID),
CONSTRAINT fk_student
FOREIGN KEY (STUDENT_ID) REFERENCES Students(STUDENT_ID),
CONSTRAINT fk_course
FOREIGN KEY (COURSE_ID) REFERENCES Courses(COURSE_ID));
INSERT INTO Departments VALUES
('BS','Buisnes','Dr.Eyal'),
('CH','Chemistry','Prof.Doron'),
('CS','Computer Science','Dr.Israel'),
('MT','Mathematics','Prof.Levi');
INSERT INTO Courses VALUES
('B-10','Marketing','CLASS',5,'BS'),
('B-40','Operations Res.','SEMIN',3,'BS'),
('C-200','Programing','LAB',4,'CS'),
('C-300','Pascal','LAB',4,'CS'),
('C-55','Data Base','CLASS',3,'CS'),
('M-100','Linear Algebra','CLASS',3,'MT'),
('M-200','Numeric Analyses','CLASS',3,'MT');
INSERT INTO Students VALUES
(105,'Moshe','Haifa'),
(107,'Eyal','Tel Aviv'),
(110,'Ran','Haifa'),
(200,'David','Tel Aviv'),
(210,'Dan','Tel Aviv'),
(240,'Ayelet','Tel Aviv'),
(245,'Yoel','Haifa'),
(310,'Tova','Jerusalem');
INSERT INTO Grades VALUES
(105,'B-40','WIN1999','B',70,70),
(105,'C-200','AUT1999','A',90,85),
(105,'C-55','SUM1998','A',58,70),
(105,'M-100','SUM1998','B',75,50),
(200,'B-10','AUT1999','A',70,65),
(200,'C-200','AUT1999','B',78,50),
(200,'M-100','SUM1998','B',90,90),
(210,'B-10','WIN1999','A',78,50),
(210,'C-200','AUT1999','A',85,80),
(210,'M-100','AUT1999','A',90,90),
(245,'B-10','AUT1999','A',80,70),
(245,'B-40','WIN1998','A',85,95),
(245,'M-100','AUT1999','A',90,80),
(310,'M-100','SUM1998','A',65,100);
Now what I'm trying to do is to print all course names and student names where their grade multiplied by 1.1 is bigger than semester grade.
Now, I manage to do it by printing the course_id and student_id but then on this result I'm trying to connect between the student_id and their names in order to actually print the student name (s_name) and course name instead (course_id)
this is the current script I have:
SELECT STUDENT_ID,COURSE_ID
FROM Grades
WHERE (Grade*1.1>GRADE_SEM)
so basically all I want is quite the same results as I get but to have
student name (s_name) and course_name instead their id's. (this is the print I get right now
Actually it's simple Join Can do that
SELECT
Students.S_Name, Courses.Course_Name,
Students.Student_ID, Courses.Course_ID
FROM
Grades
INNER JOIN Students on Students.Student_ID = Grades.Student_ID
INNER JOIN Courses on Courses.Course_ID = Grades.Course_ID
WHERE
(Grades.Grade*1.1>Grades.GRADE_SEM)
You can read Join more in here Join Documentation
You can see here for Demo = Demo

SQL Server 2014 server new to JOINS

I am new to SQL server.
I would like to ask how can I join these statements? The result should be batman, tim burton to james murrilo.
CREATE TABLE Movie(
movieId INT NOT NULL,
movieTitle CHAR(50) NOT NULL,
director CHAR(50) NOT NULL
PRIMARY KEY (movieId)
);
INSERT INTO Movie (movieId, movieTitle, director)VALUES (1, 'Batman', 'Tim Burton');
INSERT INTO Movie (movieId, movieTitle, director)VALUES (2, 'Spiderman','Sam Raimi');
CREATE TABLE Reviewer(
reviewerId INT NOT NULL,
reviewerName CHAR(50) NOT NULL,
PRIMARY KEY (reviewerId)
);
INSERT INTO Reviewer (reviewerId, reviewerName) VALUES(1, 'David Carroll');
INSERT INTO Reviewer (reviewerId, reviewerName) VALUES(2, 'James Murillo');
CREATE TABLE Movie_Reviewers(
movieId INT NOT NULL,
reviewerId INT NOT NULL,
CONSTRAINT movieReviewerPK PRIMARY KEY(movieId, reviewerId),
CONSTRAINT movieFK1 FOREIGN KEY(movieId) REFERENCES Movie,
CONSTRAINT reviewerFK1 FOREIGN KEY(reviewerId) REFERENCES Reviewer
);
INSERT INTO Movie_Reviewers (MovieId, reviewerId) VALUES(1,2);
INSERT INTO Movie_Reviewers (MovieId, reviewerId) VALUES(2,1);
SELECT Movie_Reviewers.*, Movie.MovieTitle, Movie.director, Reviewer.reviewerName
FROM Movie_Reviewers
JOIN Movie ON Movie.MovieId = Movie_Reviewers.MovieId
JOIN Reviewer ON Reviewer.reviewerId = Movie_Reviewers.MovieId
Just fix the last line - Movie_Reviewers.ReviewerID
JOIN Reviewer ON Reviewer.reviewerId = Movie_Reviewers.ReviewerId
Use where clause and there is a small mistake in your last join - what I understand from your question you need to get movie id 1 value
using your query you'll get all results for movie
SELECT Movie_Reviewers.*, Movie.MovieTitle, Movie.director, Reviewer.reviewerName
FROM Movie_Reviewers
JOIN Movie ON Movie.MovieId = Movie_Reviewers.MovieId
JOIN Reviewer ON Reviewer.reviewerId = Movie_Reviewers.reviewerId
where Movie.MovieId=1
Join with valid Primary key and Foreign key Relationship,
SELECT Movie_Reviewers.*, Movie.MovieTitle, Movie.director, Reviewer.reviewerName
FROM Movie_Reviewers
JOIN Movie ON Movie.MovieId = Movie_Reviewers.MovieId
JOIN Reviewer ON Reviewer.reviewerId = Movie_Reviewers.reviewerId

Sql table where row may only be inserted if unique column

I want to create a table which contains person, house and family, where only persons from the same family are allowed to live in the same house.
What I have so far does not work because I can only post one row with unique family and house. Is there any way to do this?
CREATE TABLE familyhouse (
person VARCHAR(64),
house VARCHAR(64),
family VARCHAR(64),
unique(house,family)
);
Example of correct table:
man,'1','1'
man2,'1','1'
man3,'1','1'
man4,'2','2'
man5,'2','2'
man6,'3','3'
Example of non-correct table:
man,'1','1'
man2,'1','1'
man3,'1','2'
I'd leverage the power of foreign keys and put the house and family in their own table (family_house) and a separate table for the residents.
CREATE TABLE family_house (
house VARCHAR(128) NOT NULL UNIQUE,
family VARCHAR(64) NOT NULL,
PRIMARY KEY (house, family)
);
CREATE TABLE residents (
person VARCHAR(64),
house VARCHAR(128),
family VARCHAR(64),
UNIQUE (person, house, family),
FOREIGN KEY (house, family) REFERENCES family_house
);
This way I can have multiple residents in the same home, but only one family to a home.
You can use a CHECK CONSTRAINT to maintain this:
CREATE TABLE familyhouse (
person VARCHAR(64),
house VARCHAR(64),
family VARCHAR(64)
);
CREATE FUNCTION CheckFamilyHouse(VARCHAR(64), VARCHAR(64))
RETURNS BOOLEAN AS $$
SELECT CASE WHEN EXISTS
( SELECT 1
FROM FamilyHouse
WHERE Family = $1
AND House != $2
)
THEN false
ELSE true
END
$$ LANGUAGE SQL;
ALTER TABLE familyHouse
ADD CONSTRAINT CHK_FamilyHouse
CHECK(CheckFamilyHouse(family, house));
With the above in place the second insert below will fail:
INSERT INTO familyhouse VALUES(1, 1, 1);
INSERT INTO FamilyHouse VALUES(2, 2, 1);
with the message:
ERROR: new row for relation "familyhouse" violates check constraint "chk_familyhouse": INSERT INTO FamilyHouse VALUES(2, 2, 1)
SQL Fiddle Example
create table house (
id serial primary key
);
create table family (
id serial primary key
);
create table house_family (
house_id integer,
family_id integer,
primary key (house_id, family_id),
foreign key (house_id) references house (id),
foreign key (family_id) references family (id)
);
create table person (
id serial primary key,
family_id integer,
house_id integer,
foreign key (house_id, family_id) references house_family (house_id, family_id)
);
insert into house values (1),(2),(3);
insert into family values (1),(2),(3);
insert into house_family values (1,1),(2,2),(3,3);
insert into person (family_id, house_id) values (1,1),(1,1);
select * from house;
id
----
1
2
3
select * from family;
id
----
1
2
3
select * from house_family;
house_id | family_id
----------+-----------
1 | 1
2 | 2
3 | 3
select * from person;
id | family_id | house_id
----+-----------+----------
5 | 1 | 1
6 | 1 | 1
Now if you try to insert a person from family_id 2 in the same house_of family_id 1:
insert into person (family_id, house_id) values (2,1);
ERROR: insert or update on table "person" violates foreign key constraint "person_house_id_fkey"
DETAIL: Key (house_id, family_id)=(1, 2) is not present in table "house_family".