How to organize tables to stare statistic of two entities? - sql

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.

Related

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.

Database Design in PostgreSQL

I am designing a database for school.
Requirements
Professors have an SSN, a name, an age, gender, a rank, and a research specialty
Professors work in exactly one department
Departments have a department number, a department name, and a main office
Departments must have one professor (known as the chairman) who runs the department
My current schema for "Professors" and "Departments"
CREATE DOMAIN SSN AS CHAR(11) CONSTRAINT validSSN CHECK (VALUE ~* "^\d{3}-\d{2}-\d{4}$");
CREATE TABLE Persons (
person_id INT PRIMARY KEY AUTO_INCREMENT,
ssn SSN NOT NULL CONSTRAINT mustBeDifferent UNIQUE,
name VARCHAR(255) NOT NULL,
age INT NOT NULL CONSTRAINT nonnegativeAge CHECK(age >= 0),
gender CHAR(1) CONSTRAINT mustBeMaleOrFemale CHECK(gender = "M" OR gender = "F") NOT NULL,
);
CREATE TABLE Professors (
ranking INT NOT NULL CONSTRAINT positiveRanking CHECK(ranking > 0),
research_specialty VARCHAR(255) NOT NULL,
department_id INT NOT NULL REFERENCES Departments(department_number)
) INHERITS(Persons);
CREATE TABLE Departments (
department_number INT PRIMARY KEY AUTO_INCREMENT,
department_name VARCHAR(255) NOT NULL,
main_office VARCHAR(255) NOT NULL,
chairman_id INT REFERENCES Professors(person_id)
);
I have a foreign key in the "Professors" table that references the "Departments" table and a foreign key in the "Departments" table that references the "Professors" table.
Is there any way that I could go about resolving this issue?
I see a few problems:
professors should not inherit from persons, but reference it with a foreign key.
Otherwise you cannot guarantee uniqueness of the primary key.
Don't store the age in persons, but the birthday.
Otherwise your data will grow invalid pretty quickly.
If there is no length limit dictated by the application, don't use varchar(255), but use text.

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

SQL how can I get list of users and departments with filter by position?

Please help me, how can i get a list of users of the department with a filter by position?
CREATE TABLE COMPANY
(
ID INT GENERATED BY DEFAULT AS IDENTITY,
NAME VARCHAR(255),
PRIMARY KEY (ID),
UNIQUE KEY COMPANY_NAME (NAME)
);
CREATE TABLE USER
(
ID INT GENERATED BY DEFAULT AS IDENTITY,
NAME VARCHAR(255),
LASTNAME VARCHAR(255),
DATE_OF_BIRTH DATE ,
PRIMARY KEY (ID),
);
CREATE TABLE POSITION
(
ID INT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
POSITION VARCHAR (50),
USERID INT NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (USERID) REFERENCES USER(ID)
);
CREATE TABLE DEPARTMENT
(
ID INT GENERATED BY DEFAULT AS IDENTITY,
USER_ID INT NOT NULL,
COMPANY_ID INT NOT NULL,
DEPARTMENT_CATEGORY VARCHAR(50),
PRIMARY KEY (ID),
FOREIGN KEY (USER_ID) REFERENCES USER(ID),
FOREIGN KEY (COMPANY_ID) REFERENCES COMPANY(ID)
);
CREATE TABLE CATEGORY
(
ID INT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
NAME VARCHAR (50),
PRIMARY KEY (ID)
);
CREATE TABLE DEPARTMENT_CATEGORY
(
DEPARTMENT_ID INT NOT NULL,
CATEGORY_ID INT NOT NULL,
FOREIGN KEY (DEPARTMENT_ID) REFERENCES DEPARTMENT(ID),
FOREIGN KEY (CATEGORY_ID) REFERENCES CATEGORY(ID)
);
Please help me!!
it look like you wanted to display results from department and position table that has both the data you need, but be specific about your filter (position) as u need to provide it in your where clause
select user_ID, department
from department as a
join user as b
on a. user_id = b. user_id
where position = 'put the specific position you wanted to be filtered here'
but your two userID columns are written differently as (User_id or USERID) correct that too not get failure result when you execute the task

Start and stop date fields vs. single date field for historical, hierarchical data

In developing a historical and hierarchical SQL table, is it better to use start and stop date fields or a single date field for every date? There are pros and cons for each, but I'm looking for evidence as to which is more optimized, elegant, and takes into account corner cases most effectively.
Example -
-- Start/Stop
create table roster (
id bigint identity primary key,
start_date date not null,
stop_date date not null,
employee_id int not null references employee (id),
supervisor_id int not null references employee (id),
unique(start_date, stop_date, employee_id)
)
-- Single Date
create table roster (
id bigint identity primary key,
row_date date not null,
employee_id int not null references employee (id),
supervisor_id int not null references employee (id),
unique(row_date, employee_id)
)