SQL tables with boolean variables - sql

I am kind of new to SQL using and i am playing with different scenarios.
My Example is as follows :
Suppose that i need to have a student enrollment system . I created the student table as follows :
create table student (net_id char(10) , first_name char(20) ,
last_name char(20) , Major char(10) , ISGraduate BOOLEAN,
primary key (net_id)
where isgraduate boolean variable measures whether a student is a graduate student or not.
I have a another entity which is professor as follows :
create table professor (net_id char(10) , first_name char(20)
, last_name char(20) , Rank char(10) , department char(20) ,
primary key (net_id))
Then if i want to model the relationship : a professor can advise many graduate students , then i might need to create a new table adviosry , But in there how can i filter only the graduate students ?
any help would be great .
Thank you.

You can create the table advisory like this:
create table advisory (
professor_id char(10),
student_id char(10),
ISGraduate BOOLEAN default 1,
foreign key (professor_id) references professor(net_id),
foreign key (student_id, ISGraduate) references student(net_id, ISGraduate),
primary key (professor_id, student_id)
);
and add a unique index in the table student for the columns net_id and ISGraduate:
create table student (
net_id char(10),
first_name char(20),
last_name char(20),
Major char(10),
ISGraduate BOOLEAN,
unique(net_id, ISGraduate),
primary key (net_id)
);
See the demo.
Also make sure that the flag foreign_keys is ON by executing:
PRAGMA foreign_keys = ON;
and get the graduate students from this table with a join to student:
select s.*
from student s inner join advisory a
on s.net_id = a.student_id

Related

PostgreSQL table join

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;

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.

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

sqlite trigger checking equality of new tuple values with subqueries

I have a database representing a school with tables such as courses, students, and enrollment. They have the following schemas:
CREATE TABLE Students(
id INT CHECK(id > 100000),
lName CHAR(20),
fName CHAR(10),
gender CHAR(1) CHECK(gender IN('F','M')),
dob DATE,
address CHAR(100),
phone INT CHECK(phone > 1000000000),
grade CHAR(1) CHECK(grade IN('K','1','2','3','4','5')),
PRIMARY KEY(id));
CREATE TABLE Courses(
id INT CHECK(id > 1000),
name CHAR(40),
grade CHAR(1) CHECK(grade IN('K','1','2','3','4','5')),
PRIMARY KEY(id)
);
CREATE TABLE Enrollment(
studentID INT REFERENCES Students(id),
courseID INT REFERENCES Courses(id),
semester CHAR(6) CHECK(semester IN('Fall','Spring')),
year INT,
letterGrade CHAR(1) CHECK(letterGrade IN('A','B','C','D','E')),
PRIMARY KEY(studentID,courseID,semester,year));
I want to create a trigger for the enrollment table that will check that the grade level of the student with the given studentID and the grade level of the course with the courseID are equal before the tuple is inserted. I've been working on this for a while and can't seem to get it to work. Could anyone point me in the right direction?
This is what I've come up with:
CREATE TRIGGER appropriateLevel
...> BEFORE INSERT ON Enrollment
...> FOR EACH ROW
...> BEGIN
...> SELECT RAISE(ABORT,'The student's grade does not match the grade level of the course.')
...> WHERE EXISTS(SELECT * FROM Students, Courses WHERE ((Students.grade = Courses.grade) AND (Students.id = NEW.studentID) AND (Courses.id = NEW.courseID)));
...> END;
Thanks!
Your trigger aborts when the grades match.
Anyway, you don't need to use EXISTS because you want to compare only one specific value from each parent table:
CREATE TRIGGER appropriateLevel
BEFORE INSERT ON Enrollment
FOR EACH ROW
BEGIN
SELECT RAISE(ABORT, 'The student''s grade does not match the course''s grade level.')
WHERE (SELECT grade FROM Students WHERE id = NEW.studentID) <>
(SELECT grade FROM Courses WHERE id = NEW.courseID);
END;

Creating table with Identity related too other column in table

I'm trying to create a table that has a primary key (Department_ID) that auto assigns(not hard). However the assignment would be based on the exsisting value in another column(Department_Name). So for example if its the department_name payroll the department_ID would be 1 for example. If I tried to insert into and had to add another payroll employee it would not auto increment. It would assign value 1 to it. I assume its constraint I am looking for, but have no idea if I'm looking at this wrong or how to write it. Here's what I have so far:
CREATE TABLE tblDepartment
(
Department_ID int NOT NULL IDENTITY,
Department_Name varchar(255) NOT NULL,
Division_Name varchar(255) NOT NULL,
City varchar(255) default 'sometown' NOT NULL,
Building int default 1 NOT NULL,
Phone varchar(255) NOT NULL,
PRIMARY KEY (Department_ID)NOT NULL,
Check (Building >=1 AND Building <= 10 )
)
CREATE TABLE tblEmployee
(
Employee_ID int NOT NULL IDENTITY,
Department_ID int ,
Employee_Name varchar(255),
Social_Security_Number varchar(255),
Work_Phone varchar(255),
Position varchar(255),
Hire_Date datetime,
Birth_Date datetime,
FOREIGN KEY (Department_ID) REFERENCES tblDepartment(Department_ID)
)
Thanks for the help!
You shouldn't need a Department record per employee. You'll only have one Department record per department. You'll insert the Department.Department_ID value from the corresponding Department record into the Employee.Department_ID field when you insert an Employee record.
An autoincrement field for Department.Department_ID should be fine.
According to your schema, you already have a constraint that enforces this.
A TRIGGER on insert into tblEmployee that reads tblDepartment and sets the key accordingly might be a solution.
What happens if an employee changes department?