Tables with multiple relationships - sql

I have two tables AdmissionExams and PeriodicalExams:
create table dbo.AdmissionExams
(
Id int identity not null
AnalysisId int null, FK to Analyses Table
ClassificationId int not null, FK to Classifications Table
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
-- Other admission exam columns
)
create table dbo.PeriodicalExams
(
Id int identity not null
AnalysisId int null, FK to Analyses Table
ClassificationId int not null, FK to Classifications Table
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
-- Other periodical exam columns
)
One exam has no Analisys or one Analisys. And one Analisys has only one Exam.
One exam has always one and only one Classification. And one Classification has only one Exam.
One exam has one and only one Student and only one Professor.
But one student and one professor can have multiple exams.
Is my business model ok? I am not sure about the FKs.
The Analysis and Classification table are the same for both type of exams.

I suggest you that use inherited table in Table per type format.
create table dbo.Exams
(
Id int identity not null
AnalysisId int null, FK to Analyses Table
ClassificationId int not null, FK to Classifications Table
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
)
create table dbo.AdmissionExams
(
Id int not null
-- Other admission exam columns
)
create table dbo.PeriodicalExams
(
Id int not null
-- Other periodical exam columns
)
ALTER TABLE dbo.AdmissionExams ADD CONSTRAINT [FK_AdmissionExams_Exam] FOREIGN KEY(Id) REFERENCES dbo.exam (Id)
ALTER TABLE dbo.PeriodicalExams ADD CONSTRAINT [FK_PeriodicalExams_Exam] FOREIGN KEY(Id) REFERENCES dbo.exam (Id)

Rather You should have one exam table and a column to define its type. Depending on the amount of information you have to capture for Classification and Analysis it might be be better to add them directly to the exam tables also (Given the 1 to 1 relationship).
create table dbo.Exams
(
Id int identity not null
ExamType varchar(20) null,
AnalysisInfo varchar(20) null,
ClassificationInfo varchar(20) null,
ProfessorId int not null, FK to Professors Table
StudentId int not null, FK to Students Table
)

Related

ALTER TABLE statement conflicted with the FOREIGN KEY constraint

When creating the foreign key I came across this error. Below is my code.
create table tblPerson(
ID int not null primary key,
Fullname varchar(50) not null,
Email varchar(50) not null,
GenderId int
)
create table tblGender (
ID int not null primary key,
Gender varchar(50) not null
)
alter table tblPerson add constraint tblPerson_GenderId_FK
foreign key (GenderId) references tblGender(ID)
You want to identify any "do not align" rows....
I have made the below.
You won't be able to add the FK constraint, if any rows come back from the SELECT query.
I have also removed the hungarian notation for "tbl". I would advise against it.
create table dbo.Person(
ID int not null primary key,
Fullname varchar(50) not null,
Email varchar(50) not null,
GenderId int )
create table dbo.Gender (
ID int not null primary key,
Gender varchar(50) not null
)
/* any rows below? your FK creation will fail */
Select *, p.GenderId as 'HoustonWeHaveAProblemValue' from dbo.Person p Where Not Exists (Select 1 from dbo.Gender g where g.ID = p.GenderId)
alter table dbo.Person add constraint Person_GenderId_FK
foreign key (GenderId) references dbo.Gender(ID)
Hi please use the following code to achieve your goal :
1-First create tblGender:
create table tblGender (
ID int not null primary key,
Gender varchar(50) not null
)
2-Then create table tblPerson with the relationship between 2 tables since the beginning:
create table tblPerson(
ID int not null primary key,
Fullname varchar(50) not null,
Email varchar(50) not null,
GenderId int references tblGender(ID)
)
works fine.

Is there a way to relationship between two table which table one has 3 unique keys and table two has 2 unique keys in SQL Server?

I want to create relation between two tables, here's my table structure
Table1:
ID INT PrimaryKey AUTO_INCREMENT,
CountryCode INT UNIQUE,
Division VARCHAR(4) UNIQUE,
SubDivision VARCHAR(10) UNIQUE
Table2:
ID INT PrimaryKey AUTO_INCREMENT,
CountryCode INT UNIQUE,
Division VARCHAR(4) UNIQUE,
ReportNo VARCHAR(10) UNIQUE
Table1:
ID |CountryCode |Division |SubDivision
-------+------------------+--------------+-----------
1 |IDN |A |A-1
2 |IDN |B |B-1
3 |IDN |B |B-2
Table2
ID |CountryCode |Division |ReportNo
-------+------------------+--------------+-----------
1 |IDN |A |Re001
2 |IDN |A |Re002
3 |IDN |B |Re003
I want to create a relationship between those two tables which table2 (CountryCode, Division) refers to table1 (CountryCode, Division).
So when I want to delete in table1 with CountryCode = IDN and Division = A, SQL will prompt error when table2 contains CountryCode = IDN and Division = A.
I had tried to create a relationship between those two tables, but SQL Server always throws this error:
The column in table 'table1' do not match an existing primary key or unique constraint
Can anyone guide me how can I create a relationship between those two tables?
Thanks in advance
You can't do it this way. SQL Server requires a unique constraint (or primary key constraint) on the target of a foreign key - and you have duplicates in the source table.
For this to work, you would need to have a separate table that references all possible (CountryCode, Division) combinations. Actually, your whole schema should be normalized into something like:
-- "top" table that stores the countries
create table countries (
country_id int primary key
name varchar(100)
);
-- the table that stores the divisions
create table divisions (
division_id int primary key,
country_id int references countries(country_id),
name varchar(100)
);
-- the table that stores the subdivisions
-- this corresponds to "table1" in your question
create table subdivisions (
subdivision_id int primary key,
division_id int references divisions(division_id),
name varchar(100)
);
-- the table that stores the reports
-- this corresponds to "table2" in your question
create table reports (
report_id int primary key,
division_id references divisions(division_id),
name varchar(100)
);
You can make the primary keys automatic by using identity columns (which is the SQL Server equivalent for MySQL's AUTO_INCREMENT).
As an example, here is how you would generate the current output that you are showing for the subdivisions:
select
sd.id,
c.name country,
d.name division,
sd.name subdivision
from subdivisions sd
inner join divisions d on d.division_id = sd.division_id
inner join countries c on c.country_id = d.country_id
As GMB has answered you cannot do it in this way because of the duplicates. GMB's answer is the best way to solving your problem. If for some reason you cannot follow his advice then maybe my answer would help.
You could use a composite primary key on the columns CountryCode, Division, SubDivision. Then add subdivision to Table2. And then reference this primary key in the foreignkey restraint. (notice that my example throws an error on purpose to show that the value cannot be deleted)
DROP TABLE IF EXISTS Table2;
DROP TABLE IF EXISTS Table1;
CREATE TABLE Table1
(ID INT IDENTITY(1,1)
, CountryCode CHAR(3)
, Division VARCHAR(4)
, SubDivision VARCHAR(10)
, CONSTRAINT PK_Table1 PRIMARY KEY(CountryCode, Division, SubDivision)
)
INSERT INTO Table1(CountryCode, Division, SubDivision)
VALUES ('IDN', 'A', 'A-1')
, ('IDN', 'B', 'B-1')
, ('IDN', 'B', 'B-2');
CREATE TABLE Table2
(ID INT IDENTITY(1,1) PRIMARY KEY
, CountryCode CHAR(3)
, Division VARCHAR(4)
, SubDivision VARCHAR(10)
, ReportNo VARCHAR(10)
, CONSTRAINT FK_CountryDivision FOREIGN KEY(CountryCode, Division, SubDivision) REFERENCES Table1(CountryCode, Division, SubDivision)
);
INSERT INTO Table2(CountryCode, Division, SubDivision, ReportNo)
VALUES ('IDN', 'A', 'A-1', 'Re001')
, ('IDN', 'B', 'B-1', 'Re002')
, ('IDN', 'B', 'B-2', 'Re003');
DELETE FROM Table1
WHERE Division = 'A';
Of course this change could add a whole set of new problems for instance when a report is for the whole division what should the subdivision value then be.
ps. i had to change up the example tables a bit because the values did not match, ie string values into an int column.
SQL fiddle
thank you for the all greats answer.
But in my design I can't doing this, because I has been wrong at the first time.
And the greats answer was from Mr. #10676716 #GMB.
-- "top" table that stores the countries
create table countries (
country_id int primary key
name varchar(100)
);
-- the table that stores the divisions
create table divisions (
division_id int primary key,
country_id int references countries(country_id),
name varchar(100)
);
-- the table that stores the subdivisions
-- this corresponds to "table1" in your question
create table subdivisions (
subdivision_id int primary key,
division_id int references divisions(division_id),
name varchar(100)
);
-- the table that stores the reports
-- this corresponds to "table2" in your question
create table reports (
report_id int primary key,
division_id references divisions(division_id),
name varchar(100)
);
Thanks again Mr. GMB.

How do i fill my table with data from 3 different tables?

So I am working on a football world cup database. These are my important tables:
CREATE TABLE Countries(
Cid SERIAL PRIMARY KEY,
Name VARCHAR(256) NOT NULL UNIQUE
);
CREATE TABLE Stadiums(
Sid SERIAL PRIMARY KEY,
Name VARCHAR(256) NOT NULL UNIQUE,
Cid INT REFERENCES Countries NOT NULL
);
CREATE TABLE Groups(
Gid SERIAL PRIMARY KEY,
Name VARCHAR(64) NOT NULL,
TYear SMALLINT REFERENCES Tournaments NOT NULL
);
CREATE TABLE Teams(
Tid SERIAL PRIMARY KEY,
Cid INT REFERENCES Countries NOT NULL,
Gid INT REFERENCES Groups NOT NULL
);
CREATE TABLE Matches(
Mid INT PRIMARY KEY,
HomeTid INT REFERENCES Teams NOT NULL,
VisitTid INT REFERENCES Teams NOT NULL,
HomeScore SMALLINT NOT NULL,
VisitScore SMALLINT NOT NULL,
MatchDate DATE NOT NULL,
MatchType VARCHAR(64) NOT NULL,
Sid INT REFERENCES Stadiums NOT NULL
);
CREATE TABLE tempmatches(
year INTEGER,
host_country VARCHAR(255),
match_id INTEGER,
type VARCHAR(255),
date DATE,
location1 VARCHAR(255),
team1 VARCHAR(255),
team2 VARCHAR(255),
score1 INTEGER,
score2 INTEGER
);
so my current problem is that I need to populate the columns HomeTid and VisitId of the Matches table with the tid's from the team's table that corresponds with the country of that team from the countries table but I'm not sure how to do that. I tried a few queries but none of them seemed to work. Has anyone an idea on how to solve this?
Using JOIN keyword you can combine 2 tables data.
Here, in this case, you have to use 3-way join.
Eg:
3-way JOIN can be used in this way:
SELECT * FROM table1 JOIN table2 ON table1.col1=table2.col2 JOIN table3 ON table3.col3=table.col1;
Here the 2 tables will get joined based on the columns mentioned after the "ON" keyword.
Here is a reference link in which JOIN is explained clearly
https://www.w3schools.com/sql/sql_join.asp
Use JOIN operation. In SQL it helps to combine several tables(queries) in one

How to organize tables to stare statistic of two entities?

For now I have only two tables
CREATE TABLE IF NOT EXISTS company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250) NOT NULL
);
CREATE TABLE IF NOT EXISTS employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250),
company_id INT,
FOREIGN KEY (company_id) REFERENCES Company (id)
);
I need to create one or two tables to store employees and companies statistic. For employee statistic I need to remember all previous companies of this employee and of cause hire dates and resign dates. For company statistic I need to remember all resigned employees. What is the best way to organize DB structure in my case?
Since you have many-to-many relationship, you need an aggregate table company_employee that will have combined primary key, so you need:
CREATE TABLE IF NOT EXISTS company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250) NOT NULL
);
CREATE TABLE IF NOT EXISTS employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250)
);
CREATE TABLE IF NOT EXISTS company_employee (
company_id INT NOT NULL,
employee_id INT NOT NULL,
hire_date DATE,
resign_date DATE,
FOREIGN KEY (company_id) REFERENCES Company (id),
FOREIGN KEY (employee_id) REFERENCES Employee (id)
);
So, if you want anything from aggregate table, just use JOIN on key of appropriate table.

SQL Logic and Aggregate Issue

I have the following problem to solve in SQL :
d) A query that provides management information on take up of the various types of activities on offer. For each type of activity, the query should show the total number of individuals who took that type of activity and the average number of individuals taking each type of activity.
Here are my tables :
CREATE TABLE accommodations
(
chalet_number int PRIMARY KEY,
chalet_name varchar(40) NOT NULL,
no_it_sleeps number(2) NOT NULL,
indivppw number(4) NOT NULL
)
CREATE TABLE supervisors
(
supervisor_number int PRIMARY KEY,
supervisor_forename varchar(30) NOT NULL,
supervisor_surname varchar(30) NOT NULL,
mobile_number varchar(11) NOT NULL
)
CREATE TABLE visitors
(
visitor_ID int PRIMARY KEY,
group_ID int NOT NULL,
forename varchar(20) NOT NULL,
surname varchar(20) NOT NULL,
dob date NOT NULL,
gender varchar(1) NOT NULL
)
CREATE TABLE activities
(
activity_code varchar(10) PRIMARY KEY,
activity_title varchar(20) NOT NULL,
"type" varchar(20) NOT NULL
)
CREATE TABLE "groups"
(
group_ID int PRIMARY KEY,
group_leader varchar(20) NOT NULL,
group_name varchar(30)
number_in_group number(2) NOT NULL
)
CREATE TABLE bookings
(
group_ID int NOT NULL,
start_date date NOT NULL,
chalet_number int NOT NULL,
no_in_chalet number(2) NOT NULL,
start_date date NOT NULL,
end_date date NOT NULL,
CONSTRAINT bookings_pk PRIMARY KEY(group_ID, chalet_number));
CREATE TABLE schedule
(
schedule_ID int PRIMARY KEY,
activity_code varchar(10) NOT NULL,
time_of_activity number(4,2) NOT NULL,
am_pm varchar(2) NOT NULL,
"date" date NOT NULL
)
CREATE TABLE activity_bookings
(
visitor_ID int NOT NULL,
schedule_ID int NOT NULL,
supervisor_number int NOT NULL,
comments varchar(200),
CONSTRAINT event_booking_pk PRIMARY KEY(visitor_ID, schedule_ID));
ALTER TABLE visitors
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE Schedule
ADD FOREIGN KEY (activity_code)
REFERENCES activities(activity_code)
ALTER TABLE bookings
ADD FOREIGN KEY (group_ID)
REFERENCES "groups"(group_ID)
ALTER TABLE bookings
ADD FOREIGN KEY (chalet_number)
REFERENCES accommodations(chalet_number)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (visitor_ID)
REFERENCES visitors(visitor_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (schedule_ID)
REFERENCES schedule(schedule_ID)
ALTER TABLE activity_bookings
ADD FOREIGN KEY (supervisor_number)
REFERENCES supervisors(supervisor_number)
I have the following solution:
SELECT activities."type", 'overalltotal' AS OT, ('overalltotal' / 'activities') AS AVG
FROM activities, schedule
WHERE 'overalltotal' = (SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type"
)
AND 'activities' = (SELECT COUNT(DISTINCT activities."type")
FROM activities
)
AND schedule.activity_code = activities.activity_code
GROUP BY activities."type";
I have implemented sample data and code to check the variables above:
SELECT SUM(COUNT(schedule_ID))
FROM activities, schedule
WHERE schedule.activity_code = activities.activity_code
GROUP BY activities."type";
Result : 20
SELECT COUNT(DISTINCT activities."type")
FROM activities;
Result : 5
However when running the code :
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause:
*Action:
EDIT:
Using Dave's Code i have the following output:
Snowboarding 15
sledding 19
Snowmobiling 6
Ice Skating 5
Skiing 24
How would i do the final part of the question?
and the average number of individuals taking each type of activity.
You must use double quotes around column names in Oracle, not single quotes. For example, "overalltotal". Single quotes are for text strings, which is why you're getting an invalid number error.
EDIT: This is probably the type of query you want to use:
SELECT activities."type", COUNT(*) AS total, COUNT(*)/(COUNT(*) OVER ()) AS "avg"
FROM activities a
JOIN schedule s ON a.activity_code=s.activity_code
JOIN activity_bookings ab ON s.schedule_ID=ab.schedule_ID
GROUP BY activities."type";
Basically, because each activity booking has one visitor id, we want to get all the activity bookings for each activity. We have to go through schedule to do that. They we group the rows by the activity type and count how many activity bookings we have for each type.