PostgreSQL table join - sql

I have a lecture attendance database as an uni project.
As one of views, i came up with idea that I could make missed_lectures view with all records of Not attended or Sick attendance types. When I am making this query, it returns 2,5k rows, which is not correct.
Query looks like this
CREATE OR REPLACE VIEW missed_lectures AS
SELECT CONCAT(s.student_name, ' ', s.student_surname) AS "Student", sc.course_title AS "Study course", atp.attendance_type AS "Attendance type", a.record_date AS "Date"
FROM students AS s, study_courses AS sc, attendance_type AS atp, attendance AS a
WHERE
s.student_id=a.student_id AND
sc.course_id=a.course_id AND
a.attendance_type_id=atp.attendance_type_id AND
a.attendance_type_id=(SELECT attendance_type_id FROM attendance_type WHERE attendacne_type='Sick') OR
a.attendance_type_id=(SELECT attendance_type_id FROM attendance_type WHERE attendance_type='Not attended')
GROUP BY s.student_name, s.student_surname, sc.course_title, atp.attendance_type, a.record_date;
This is the last query I came up with, but as I mentioned earlier, it returns 2,5k rows with incorrect data.
Can anybody spot the issue here?
EDIT:
table students is
CREATE TABLE students(
student_id serial PRIMARY KEY NOT NULL,
student_name VARCHAR(30) NOT NULL,
student_surname VARCHAR(35) NOT NULL,
matriculation_number VARCHAR(7) NOT NULL CHECK(matriculation_number ~ '[A-Z]{2}[0-9]{5}'),
faculty_id INT NOT NULL,
course INT NOT NULL,
phone_number CHAR(8) CHECK(phone_number ~ '^2{1}[0-9]{7}'),
email VARCHAR(35),
gender VARCHAR(10)
);
sample data:
INSERT INTO students (student_name, student_surname, matriculation_number, faculty_id, course, phone_number, email, gender)
VALUES
('Sandis','Bērziņš','IT19047',7,1,'25404213','sandis.berzins#gmail.com','man'),
('Einārs','Kļaviņš','IT19045',7,1,'24354654','einars.klavins#gmail.com','man'),
('Jana','Lapa','EF18034',8,2,'26224941','lapajana#inbox.lv','woman'),
('Sanija','Bērza','EF18034',8,2,'24543433','berzasanija#inbox.lv','woman'),
('Valdis','Sijāts','TF19034',4,1,'25456545','valdis.sijats#gmail.com','man'),
('Jānis','Bānis','IT17034',7,3,'24658595','banis.janis#inbox.lv','man');
table study_courses is
CREATE TABLE study_courses(
course_id serial PRIMARY KEY NOT NULL,
course_title VARCHAR(55) NOT NULL,
course_code VARCHAR(8) NOT NULL CHECK(course_code ~ '[a-zA-Z]{4}[0-9]{4}'),
credit_points INT
);
sample data:
INSERT INTO study_courses (course_title, course_code, credit_points)
VALUES
('Fundamentals of Law','JurZ2005',2),
('Database technologies II','DatZ2005',2),
('Product processing','PārZ3049',4),
('Arhitecture','Arhi3063',3),
('Forest soils','LauZ1015',4);
Table attendance_type is:
CREATE TABLE attendance_type(
attendance_type_id serial PRIMARY KEY NOT NULL,
attendance_type VARCHAR(15) NOT NULL
);
sample data:
INSERT INTO attendance_type (attendance_type)
VALUES
('Attended'),
('Not attended'),
('Late'),
('Sick');
table attendance is:
CREATE TABLE attendance(
record_id serial PRIMARY KEY NOT NULL,
student_id INT NOT NULL,
course_id INT NOT NULL,
attendance_type_id INT NOT NULL,
lecturer_id INT,
lecture_type_id INT NOT NULL,
audience_id INT NOT NULL,
record_date DATE NOT NULL
);
sample data:
INSERT INTO attendance (student_id, course_id, attendance_type_id, lecturer_id, lecture_type_id, audience_id, record_date)
VALUES
(1,2,1,1,1,14,'20-05-2020'),
(2,2,1,1,1,14,'20-05-2020'),
(6,9,1,13,2,2,'20-05-2020'),
(22,9,2,13,2,2,'20-05-2020'),
(24,9,3,13,2,2,'20-05-2020');
Hoping this will help.

The problem is that OR condition in your WHERE clause.
You have to surround it by parentheses if you're going to do it that way.
However, you're already querying the attendance_type table so you can just use it to filter for those two attendance type conditions.
SELECT
CONCAT(s.student_name, ' ', s.student_surname) AS "Student",
sc.course_title AS "Study course",
atp.attendance_type AS "Attendance type",
a.record_date AS "Date"
FROM
students AS s, study_courses AS sc,
attendance_type AS atp, attendance AS a
WHERE
s.student_id=a.student_id AND
sc.course_id=a.course_id AND
a.attendance_type_id=atp.attendance_type_id AND
-- filter for these two conditions without subqueries
atp.attendance_type in ('Sick','Not attended')
GROUP BY
CONCAT(s.student_name, ' ', s.student_surname), sc.course_title,
atp.attendance_type, a.record_date;

Related

How to implement a double constraint in SQL Server?

I am designing a database project that holds records for an alumni association. My goal was to make sure that the names in the awards table only come from those who have been nominated in the alumni table (where Award_Nominated acts as a Boolean). I have tried using two booleans, one for nomination and another for winning, but that still leaves a possibility for a logical error, i.e. one can be an award winner without getting nominated. My question is how can I make sure that the award winner names only come from the alumni name values with Award_nominated as true.
The relevant tables are declared below:
CREATE TABLE Alumni
(
Alumni_ID int NOT NULL IDENTITY(1,1),
First_Name varchar(20) UNIQUE NOT NULL,
Last_Name varchar(20) UNIQUE NOT NULL,
Graduation_Year int NOT NULL,
Course_taken varchar(255) NOT NULL,
Award_Nominated bit,
Phone_Number int NOT NULL,
Email_Address varchar(255) NOT NULL,
PRIMARY KEY (Alumni_ID, First_Name, Last_Name)
);
CREATE TABLE Awards
(
Award_year int NOT NULL,
Chapters varchar(255),
Award_Winner_First_Name varchar(20) NOT NULL,
Award_Winner_Last_Name varchar(20) NOT NULL,
FOREIGN KEY (Award_Winner_First_Name) REFERENCES Alumni(First_Name),
FOREIGN KEY (Award_Winner_Last_Name) REFERENCES Alumni(Last_Name),
Award_purpose varchar(255) NOT NULL
);
Couple points:
simplify the Alumni table's primary key to be just the Alumni_ID
Don't make first and last name unique - really bad idea ....
reference the Awards table to the Alumni table solely based on the Alumni_ID - not on first and last name ....
don't duplicate the first and last name of the alumni into the Awards table -
if need be, you can get it be a JOIN to the Alumni table
I'd go with this:
CREATE TABLE dbo.Alumni
(
Alumni_ID int NOT NULL IDENTITY(1,1)
CONSTRAINT PK_Alumni PRIMARY KEY CLUSTERED,
First_Name varchar(20) NOT NULL,
Last_Name varchar(20) NOT NULL,
Graduation_Year int NOT NULL,
Course_taken varchar(255) NOT NULL,
Award_Nominated bit,
Phone_Number int NOT NULL,
Email_Address varchar(255) NOT NULL
);
CREATE TABLE dbo.Awards
(
Award_year int NOT NULL,
Alumni_ID int NOT NULL
CONSTRAINT FK_Award_Alumni REFERENCES dbo.Alumni(Alumni_ID),
Chapters varchar(255),
Award_purpose varchar(255) NOT NULL
);
Don't duplicate the names in the Awards table. Reference the Alumni ID and join.
CREATE TABLE Alumni (
Alumni_ID int not null identity(1,1),
-- It's possible to have two alumni with the same name.
-- And also to have names longer than 20 characters.
First_Name varchar(255) not null,
Last_Name varchar(255) not null,
Graduation_Year int not null,
Course_taken varchar(255) not null,
Phone_Number int not null,
Email_Address varchar(255) not null,
-- Just the Alumni_ID is sufficient
PRIMARY KEY (Alumni_ID)
);
CREATE TABLE Awards (
Award_year int not null,
Chapters varchar(255),
-- Only reference the ID
Alumni_ID int not null,
FOREIGN key (Alumni_ID) REFERENCES Alumni(Alumni_ID),
Award_purpose varchar(255) not null
);
Then join with Alumni to get their names.
select First_Name, Last_Name, Awards.*
from Awards
join Alumni on Awards.Alumni_ID = Alumni.Alumni_ID

Adding Rows to a table based on other Table data

I am trying to Create a table which pulls data from other tables.
For my instance I have 5 students.
Each student student takes 3 subjects (Maths, English and Science)
Each subject has 3 tests.
Which means all 5 students take a total of 9 Tests each throughout the 3 subjects.
I have created the Student Table, the Subject Table and the Test Table.
I now am trying to create the Student_Results Table whereby I need to have All 9 tests for all 5 students in one table which will display their given result for their tests.
I have been struggling to get this right.
See tables I created below.
CREATE TABLE DBO.STUDENTS
(
STUDENT_ID VARCHAR(15) PRIMARY KEY,
STUDENT_FIRSTNAME VARCHAR(255) NOT NULL,
STUDENT_SURNAME VARCHAR(255) NOT NULL,
STUDENT_SCORE_AVERAGE VARCHAR(30)
);
-- Creating the 'Subjects' Table
CREATE TABLE DBO.SUBJECTS
(
SUBJECT_ID VARCHAR(12) PRIMARY KEY,
SUBJECT_NAME VARCHAR(30) NOT NULL,
SUBJECT_AVERAGE VARCHAR(30)
);
-- Creating the 'Tests' Table
CREATE TABLE DBO.TESTS
(
TEST_ID VARCHAR(12) PRIMARY KEY,
TEST_NAME VARCHAR(30) NOT NULL,
TEST_DESCRIPTION VARCHAR(50),
TEST_AVERAGE VARCHAR(3)
);
-- Creating the 'Student_Score' Table
CREATE TABLE DBO.STUDENT_SCORES
(
RESULT_ID VARCHAR (12) PRIMARY KEY,
STUDENT_ID VARCHAR(12) ,
TEST_ID VARCHAR(12),
STUDENT_SCORE VARCHAR(30)
);
create table #TempStudent
(
STUDENT_KEY INT identity (10000000,1),
STUDENT_ID AS CONCAT('STD',STUDENT_KEY),
STUDENT_FIRSTNAME VARCHAR(255),
STUDENT_SURNAME VARCHAR(255)
)
INSERT INTO #TempStudent
VALUES ( 'Daenerys' , 'Targaryen' ),
( 'Jon' , 'Snow' ),
( 'Gregor' , 'Clegane' ),
( 'Arya' , 'Stark' ),
( 'Cersei' , 'Lannister' )
INSERT INTO STUDENTS (STUDENT_ID, STUDENT_FIRSTNAME , STUDENT_SURNAME)
SELECT STUDENT_ID, STUDENT_FIRSTNAME, STUDENT_SURNAME
FROM #TempStudent
create table #TempSubject
(
SUBJECT_KEY INT identity (10000000,1),
SUBJECT_ID AS CONCAT('SUB',SUBJECT_KEY),
SUBJECT_NAME VARCHAR(255)
)
INSERT INTO #TempSubject
VALUES ('Maths'),
('Science'),
('English')
INSERT INTO SUBJECTS (SUBJECT_ID, SUBJECT_NAME )
SELECT SUBJECT_ID, SUBJECT_NAME
FROM #TempSubject
create table #TempTest
(
TEST_KEY INT identity (100,1),
TEST_ID AS CONCAT('TST',TEST_KEY),
TEST_NAME VARCHAR(255),
TEST_DESCRIPTION VARCHAR(255)
)
INSERT INTO #TempTest
VALUES ('Maths 1', 'Geometry'),
('Maths 2', 'Algebra'),
('Maths 3', 'Fractions'),
('Science 1', 'Astronomy'),
('Science 2', 'Biology'),
('Science 3', 'Chemistry'),
('English 1', 'Grammer'),
('English 2', 'Spelling'),
('English 3', 'Literature')
INSERT INTO TESTS(TEST_ID, TEST_NAME , TEST_DESCRIPTION )
SELECT TEST_ID, TEST_NAME, TEST_DESCRIPTION
FROM #TempTest
create table #TempScoreSubmission
(
SCORE_KEY INT identity (1234,1),
RESULT_ID AS CONCAT('RES',SCORE_KEY)
)
I don't know where you want to go with all that temporary tables and why don't you just create the actual tables with the primary key as an identity and directly insert into them... But to get all pairs of student ID and test ID you can use a cross join. I believe that is what you're searching for.
SELECT s.student_id,
t.test_id
FROM dbo.students s
CROSS JOIN dbo.tests t;

Arithmetic overflow error converting expression to data type int, How do I resolve this?

This is the code that created the table.
CREATE TABLE CUSTOMERS
(
Customer_ID INT NOT NULL,
CHECK(Customer_ID <= 11),
First_Name varchar(20) NOT NULL,
Last_Name varchar(30),
Home_Street varchar(30),
Home_City varchar(20),
Home_State varchar(2),
Home_Zip varchar(5),
PhoneNumber varchar(11) NOT NULL
);
ALTER TABLE CUSTOMERS
ADD CONSTRAINT PK_CUSTOMERS PRIMARY KEY(Customer_ID);
Then I try to insert data (using this code) into the table and that is where I get this error.
INSERT INTO dbo.CUSTOMERS(Customer_ID, First_Name, Last_Name, Home_Street, Home_City, Home_State, Home_Zip, PhoneNumber)
VALUES (11223344556, 'John', 'Doe', '1234 Hand Street', 'Wahiawa', 'HI', 96786, 2535551267);
What am I doing wrong and what can I do to fix this issue?
AS per my understanding you are checking length of Customer_ID <=11 so you should mention len(Customer_ID)<=11 it will work and you should alter datatype of Customer_ID int to bigint
CREATE TABLE CUSTOMERS
(
Customer_ID bigINT NOT NULL,
CHECK(len(Customer_ID)<=11),
First_Name varchar(20) NOT NULL,
Last_Name varchar(30),
Home_Street varchar(30),
Home_City varchar(20),
Home_State varchar(2),
Home_Zip varchar(5),
PhoneNumber varchar(11) NOT NULL
);
ALTER TABLE CUSTOMERS
ADD CONSTRAINT PK_CUSTOMERS
PRIMARY KEY(Customer_ID);
INSERT INTO dbo.CUSTOMERS(Customer_ID,First_Name,Last_Name,Home_Street,
Home_City,Home_State,Home_Zip,PhoneNumber)
VALUES(11223344556,'John','Doe','1234 Hand Street',
'Wahiawa','HI',96786,2535551267);
You need customer id to be bigint:
CREATE TABLE CUSTOMERS
(
Customer_ID BIGINT NOT NULL,
CHECK(Customer_ID<=11),
First_Name varchar(20) NOT NULL,
Last_Name varchar(30),
Home_Street varchar(30),
Home_City varchar(20),
Home_State varchar(2),
Home_Zip varchar(5),
PhoneNumber varchar(11) NOT NULL
);
ALTER TABLE CUSTOMERS
ADD CONSTRAINT PK_CUSTOMERS
PRIMARY KEY(Customer_ID);
The problem may be due to CHECK(Customer_ID<=11) since Customer_ID id integer datatype the server may check for integer validation and not length validation. Try to change the validation.

Foreign Key issue SQL

I cant figure out why this is not compiling It has to do with the foreign key somehow:
Drop Table Employee;
Drop Table Department;
Create Table Employee(
EmpNr int not null primary key,
EmpName Varchar(35) not null,
Dept Varchar (2) not null,
Gender char not null
);
Create Table Department(
DeptCode Varchar (2) not null primary key,
DeptName Varchar (35) not null,
Foreign Key (DeptCode) references Employee (Dept)
);
insert into Employee values (001, 'HagarT','DV','M'),
(002, 'WongS','DV','F'),
(003, 'Jones','MK','F'),
(004, 'MifuneK','SL','M');
insert into Department values ('DV', 'Development'),
('MK', 'Marketing'),
('RS', 'Research'),
('SL', 'Sales');
You need Dept be PRIMARY KEY or UNIQUE to work as FK
Create Table Employee(
EmpNr int not null primary key,
EmpName Varchar(35) not null,
Dept Varchar (2) unique not null,
Gender char not null
);
As you can see your Employee has two rows with 'DV' so which will be foreign for the Department?
I think you want is
Create Table Employee(
EmpNr int not null primary key,
EmpName Varchar(35) not null,
Dept Varchar (2) not null,
Gender char not null,
Foreign Key (Dept) references Department (DeptCode)
);

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.