diff --git a/cmd/app/main.go b/cmd/app/main.go new file mode 100644 index 0000000..4761caa --- /dev/null +++ b/cmd/app/main.go @@ -0,0 +1,182 @@ +package main + +import ( + "assignment_1_gorm" + "fmt" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +// main connects to database and does the exercises in sol-1.sql and sol-2.sql +func main() { + // Connect to the MySQL database + dsn := "quangmx:2511@tcp(127.0.0.1:3306)/engineerpro?charset=utf8mb4&parseTime=True&loc=Local" + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + panic("Failed to connect to database") + } + + initDatabase(db) + + // Những cặp student-professor có dạy học nhau và số lớp mà họ có liên quan + related_stud_prof(db) + + // Những course (distinct) mà 1 professor cụ thể đang dạy + teaching_courses(db, 1) + + // // TODO: Implement this + // // Những course (distinct) mà 1 student cụ thể đang học + // studying_courses(db, 1) + + // // TODO: Implement this + // // điểm số là A, B, C, D, E, F tương đương với 10, 8, 6, 4, 2, 0 + // convert_grade(db) + + // // TODO: Implement this + // // điểm số trung bình của 1 học sinh cụ thể (quy ra lại theo chữ cái, và xếp loại học lực (weak nếu avg < 5, average nếu >=5 < 8, good nếu >=8 ) + // stud_avg_grade(db, 1) + + // // TODO: Implement this + // // điểm số trung bình của các class (quy ra lại theo chữ cái) + // class_avg_grade(db) + + // // TODO: Implement this + // // điểm số trung bình của các course (quy ra lại theo chữ cái) + // course_avg_grade(db) + +} + +// initDatabase creates tables and adds records +func initDatabase(db *gorm.DB) { + // Delete tables if existed + db.Migrator().DropTable(&assignment_1_gorm.Professor{}) + db.Migrator().DropTable(&assignment_1_gorm.Student{}) + db.Migrator().DropTable(&assignment_1_gorm.Course{}) + db.Migrator().DropTable(&assignment_1_gorm.Class{}) + db.Migrator().DropTable(&assignment_1_gorm.Enroll{}) + fmt.Println("Tables deleted successfully...") + + // Create tables + db.Migrator().CreateTable(&assignment_1_gorm.Professor{}) + db.Migrator().CreateTable(&assignment_1_gorm.Student{}) + db.Migrator().CreateTable(&assignment_1_gorm.Course{}) + db.Migrator().CreateTable(&assignment_1_gorm.Class{}) + db.Migrator().CreateTable(&assignment_1_gorm.Enroll{}) + fmt.Println("Tables created successfully...") + + // Create records + var result *gorm.DB + professors := []assignment_1_gorm.Professor{ + {FirstName: "Albus", LastName: "Dumbledore"}, + {FirstName: "Severus", LastName: "Snape"}, + {FirstName: "Alastor", LastName: "Moody"}, + } + result = db.Create(&professors) + if result.Error != nil { + panic(result.Error) + } + + students := []assignment_1_gorm.Student{ + {FirstName: "Harry", LastName: "Potter", Street: "Privet Drive 1", City: "London", Zip: "100000"}, + {FirstName: "Hermione", LastName: "Granger", Street: "Privet Drive 2", City: "London", Zip: "200000"}, + {FirstName: "Ron", LastName: "Weasly", Street: "Privet Drive 3", City: "London", Zip: "300000"}, + } + result = db.Create(&students) + if result.Error != nil { + panic(result.Error) + } + + courses := []assignment_1_gorm.Course{ + {Name: "Physical Education"}, + {Name: "Quidditch"}, + {Name: "Defence Against the Dark Arts"}, + {Name: "Potion"}, + } + result = db.Create(&courses) + if result.Error != nil { + panic(result.Error) + } + + classes := []assignment_1_gorm.Class{ + {Name: "PE1", ProfessorID: 1, CourseID: 1, RoomLoc: "001", RoomCap: "100"}, + {Name: "QD1", ProfessorID: 2, CourseID: 2, RoomLoc: "002", RoomCap: "200"}, + {Name: "DA1", ProfessorID: 3, CourseID: 3, RoomLoc: "003", RoomCap: "300"}, + {Name: "DA2", ProfessorID: 3, CourseID: 3, RoomLoc: "004", RoomCap: "400"}, + {Name: "PT1", ProfessorID: 3, CourseID: 4, RoomLoc: "005", RoomCap: "500"}, + } + result = db.Create(&classes) + if result.Error != nil { + panic(result.Error) + } + + enrolls := []assignment_1_gorm.Enroll{ + {StudentID: 1, ClassID: 2, Grade: "B"}, + {StudentID: 2, ClassID: 1, Grade: "A"}, + {StudentID: 2, ClassID: 2, Grade: "A"}, + {StudentID: 2, ClassID: 3, Grade: "A"}, + {StudentID: 3, ClassID: 1, Grade: "C"}, + {StudentID: 3, ClassID: 3, Grade: "D"}, + {StudentID: 1, ClassID: 4, Grade: "D"}, + {StudentID: 2, ClassID: 4, Grade: "D"}, + {StudentID: 3, ClassID: 4, Grade: "D"}, + } + result = db.Create(&enrolls) + if result.Error != nil { + panic(result.Error) + } + + fmt.Println("Records created successfully...") +} + +// Những cặp student-professor có dạy học nhau và số lớp mà họ có liên quan +func related_stud_prof(db *gorm.DB) { + type Record struct { + StudentID int `gorm:"column:stud_id"` + ProfessorID int `gorm:"column:prof_id"` + Count int `gorm:"column:num_class"` + } + var records []Record + query := ` +select + distinct stud_id, + prof_id, + count(*) as num_class +from + Class + join Enroll using (class_id) +group by + stud_id, + prof_id +order by + stud_id;` + db.Raw(query).Scan(&records) + + // Print to console + fmt.Println("\nNhững cặp student-professor có dạy học nhau và số lớp mà họ có liên quan") + for _, record := range records { + fmt.Printf("%+v\n", record) + } +} + +// Những course (distinct) mà 1 professor cụ thể đang dạy +func teaching_courses(db *gorm.DB, prof_id int) { + type Record struct { + CourseID int `gorm:"column:course_id"` + } + var records []Record + query := ` +select + distinct course_id +from + Class +where + prof_id = ?;` + db.Raw(query, prof_id).Scan(&records) + + // Print to console + fmt.Printf("\nNhững course (distinct) mà professor %d đang dạy\n", prof_id) + for _, record := range records { + fmt.Printf("%+v\n", record) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..68854eb --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module assignment_1_gorm + +go 1.20 + +require gorm.io/gorm v1.25.1 + +require github.com/go-sql-driver/mysql v1.7.0 // indirect + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + gorm.io/driver/mysql v1.5.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bf8c9d9 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= +gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= +gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/model.go b/model.go new file mode 100644 index 0000000..11169cd --- /dev/null +++ b/model.go @@ -0,0 +1,112 @@ +package assignment_1_gorm + +// CREATE TABLE Professor ( +// +// prof_id INT AUTO_INCREMENT, +// prof_fname VARCHAR(50), +// prof_lname VARCHAR(50), +// PRIMARY KEY (prof_id) +// +// ); +type Professor struct { + ID uint32 `gorm:"column:prof_id;type:int(32);primary_key;auto_increment"` + FirstName string `gorm:"column:prof_fname;type:varchar(50)"` + LastName string `gorm:"column:prof_lname;type:varchar(50)"` +} + +func (Professor) TableName() string { + return "Professor" +} + +// CREATE TABLE Student ( +// +// stud_id INT AUTO_INCREMENT, +// stud_fname VARCHAR(50), +// stud_lname VARCHAR(50), +// stud_street VARCHAR(255), +// stud_city VARCHAR(50), +// stud_zip VARCHAR(10), +// PRIMARY KEY (stud_id) +// +// ); +type Student struct { + ID uint32 `gorm:"column:stud_id;type:int(32);primary_key;auto_increment"` + FirstName string `gorm:"column:stud_fname;type:varchar(50)"` + LastName string `gorm:"column:stud_lname;type:varchar(50)"` + Street string `gorm:"column:stud_street;type:varchar(255)"` + City string `gorm:"column:stud_city;type:varchar(50)"` + Zip string `gorm:"column:stud_zip;type:varchar(10)"` +} + +func (Student) TableName() string { + return "Student" +} + +// CREATE TABLE Course ( +// +// course_id INT AUTO_INCREMENT, +// course_name VARCHAR(255), +// PRIMARY KEY (course_id) +// +// ); +type Course struct { + ID uint32 `gorm:"column:course_id;type:int(32);primary_key;auto_increment"` + Name string `gorm:"column:course_name;type:varchar(255)"` +} + +func (Course) TableName() string { + return "Course" +} + +// -- Class and Room are joined into 1 table Class +// CREATE TABLE Class ( +// +// class_id INT AUTO_INCREMENT, +// class_name VARCHAR(255), +// prof_id INT, +// course_id INT, +// room_loc VARCHAR(50), +// room_cap VARCHAR(50), +// PRIMARY KEY (class_id), +// FOREIGN KEY (prof_id) REFERENCES Professor(prof_id), +// FOREIGN KEY (course_id) REFERENCES Course(course_id) +// +// ); +type Class struct { + ID uint32 `gorm:"column:class_id;type:int(32);primary_key;auto_increment"` + Name string `gorm:"column:class_name;type:varchar(255)"` + ProfessorID uint32 `gorm:"column:prof_id;type:int(32)"` + CourseID uint32 `gorm:"column:course_id;type:int(32)"` + RoomLoc string `gorm:"column:room_loc;type:varchar(50)"` + RoomCap string `gorm:"column:room_cap;type:varchar(50)"` + + Professor Professor `gorm:"foreign_key:prof_id;references:prof_id"` + Course Course `gorm:"foreign_key:course_id;references:course_id"` +} + +func (Class) TableName() string { + return "Class" +} + +// CREATE TABLE Enroll ( +// +// stud_id INT, +// class_id INT, +// grade VARCHAR(3), +// PRIMARY KEY (stud_id, class_id), +// FOREIGN KEY (stud_id) REFERENCES Student(stud_id), +// FOREIGN KEY (class_id) REFERENCES Class(class_id) +// +// ); +type Enroll struct { + StudentID int `gorm:"column:stud_id;type:int(32);primary_key"` + ClassID int `gorm:"column:class_id;type:int(32);primary_key"` + Grade string `gorm:"column:grade;type:varchar(3)"` + + Student Student `gorm:"foreign_key:stud_id;references:stud_id"` + Class Class `gorm:"foreign_key:class_id;references:class_id"` +} + +func (Enroll) TableName() string { + return "Enroll" +} diff --git a/sol-1.sql b/sol-1.sql new file mode 100644 index 0000000..24fe52e --- /dev/null +++ b/sol-1.sql @@ -0,0 +1,39 @@ +-- Solution for Capital Gain/Loss +select + stock_name, + sum( + case + when operation = "Buy" then - price + else price + end + ) as capital_gain_loss +from + Stocks +group by + stock_name; + +-- Solution for Count Salary Categories +select + "Low Salary" as "category", + count(*) as "accounts_count" +from + Accounts +where + Accounts.income < 20000 +union +select + "Average Salary" as "category", + count(*) as "accounts_count" +from + Accounts +where + income >= 20000 + and income <= 50000 +union +select + "High Salary" as "category", + count(*) as "accounts_count" +from + Accounts +where + income > 50000; \ No newline at end of file diff --git a/sol-2.sql b/sol-2.sql new file mode 100644 index 0000000..f181320 --- /dev/null +++ b/sol-2.sql @@ -0,0 +1,203 @@ +-- Create tables +drop table if exists Enroll; + +drop table if exists Class; + +drop table if exists Professor; + +drop table if exists Student; + +drop table if exists Course; + +create table Professor ( + prof_id int auto_increment, + prof_fname varchar(50), + prof_lname varchar(50), + primary key (prof_id) +); + +create table Student ( + stud_id int auto_increment, + stud_fname varchar(50), + stud_lname varchar(50), + stud_street varchar(255), + stud_city varchar(50), + stud_zip varchar(10), + primary key (stud_id) +); + +create table Course ( + course_id int auto_increment, + course_name varchar(255), + primary key (course_id) +); + +-- Class and Room are joined into 1 table Class +create table Class ( + class_id int auto_increment, + room_id int not NULL unique, + class_name varchar(255), + prof_id int, + course_id int, + room_loc varchar(50), + room_cap varchar(50), + primary key (class_id), + foreign key (prof_id) references Professor(prof_id), + foreign key (course_id) references Course(course_id) +); + +create table Enroll ( + stud_id int, + class_id int, + grade varchar(3), + primary key (stud_id, class_id), + foreign key (stud_id) references Student(stud_id), + foreign key (class_id) references Class(class_id) +); + +-- Add records +-- Insert to Professor +insert into + Professor +values + (NULL, 'Albus', 'Dumbledore'); + +insert into + Professor +values + (NULL, 'Severus', 'Snape'); + +insert into + Professor +values + (NULL, 'Alastor', 'Moody'); + +-- Insert to Student +insert into + Student +values + ( + NULL, + "Harry", + "Potter", + "Privet Drive 1", + "London", + "100000" + ); + +insert into + Student +values + ( + NULL, + "Hermione", + "Granger", + "Privet Drive 2", + "London", + "200000" + ); + +insert into + Student +values + ( + NULL, + "Ron", + "Weasly", + "Privet Drive 3", + "London", + "300000" + ); + +-- Insert to Course +insert into + Course +values + (NULL, "Physical Education"); + +insert into + Course +values + (NULL, "Quidditch"); + +insert into + Course +values + (NULL, "Defence Against the Dark Arts"); + +insert into + Course +values + (NULL, "Potion"); + +-- Insert to Class +insert into + Class +values + (NULL, 1, "PE1", 1, 1, "001", "100"); + +insert into + Class +values + (NULL, 2, "QD1", 2, 2, "002", "200"); + +insert into + Class +values + (NULL, 3, "DA1", 3, 3, "003", "300"); + +insert into + Class +values + (NULL, 4, "DA2", 3, 3, "004", "400"); + +insert into + Class +values + (NULL, 5, "PT1", 3, 4, "005", "500"); + +-- Insert to Enroll +insert into + Enroll +values + (1, 2, "B"); + +insert into + Enroll +values + (2, 1, "A"); + +insert into + Enroll +values + (2, 2, "A"); + +insert into + Enroll +values + (2, 3, "A"); + +insert into + Enroll +values + (3, 1, "C"); + +insert into + Enroll +values + (3, 3, "D"); + +insert into + Enroll +values + (1, 4, "D"); + +insert into + Enroll +values + (2, 4, "D"); + +insert into + Enroll +values + (3, 4, "D"); \ No newline at end of file diff --git a/sol-3.sql b/sol-3.sql new file mode 100644 index 0000000..8ce304f --- /dev/null +++ b/sol-3.sql @@ -0,0 +1,113 @@ +-- Những cặp student-professor có dạy học nhau và số lớp mà họ có liên quan +select + distinct stud_id, + prof_id, + count(*) as num_class +from + Class + join Enroll using (class_id) +group by + stud_id, + prof_id +order by + stud_id; + +-- Những course (distinct) mà 1 professor cụ thể đang dạy +select + distinct course_id +from + Class +where + prof_id = 3; + +-- Những course (distinct) mà 1 student cụ thể đang học +select + distinct course_id +from + Enroll + join Class using (class_id) +where + stud_id = 3; + +-- điểm số là A, B, C, D, E, F tương đương với 10, 8, 6, 4, 2, 0 +create +or replace view Enroll_Grade as +select + stud_id, + class_id, + ( + case + when grade = "A" then 10 + when grade = "B" then 8 + when grade = "C" then 6 + when grade = "D" then 4 + when grade = "E" then 2 + else 0 + end + ) as score +from + Enroll; + +select + * +from + Enroll_Grade; + +-- điểm số trung bình của 1 học sinh cụ thể (quy ra lại theo chữ cái, và xếp loại học lực (weak nếu avg < 5, average nếu >=5 < 8, good nếu >=8 ) +select + stud_id, + avg(score) as average_score, + ( + case + when avg(score) >= 8 then "Good" + when avg(score) >= 5 then "Average" + else "Weak" + end + ) as classification +from + Enroll_Grade +where + stud_id = 2; + +-- điểm số trung bình của các class (quy ra lại theo chữ cái) +select + class_id, + class_name, + avg(score) as average_score, + ( + case + when avg(score) >= 9 then "A" + when avg(score) >= 8 then "B" + when avg(score) >= 6 then "C" + when avg(score) >= 4 then "D" + when avg(score) >= 2 then "E" + else "F" + end + ) as average_grade +from + Enroll_Grade + join Class using (class_id) +group by + class_id; + +-- điểm số trung bình của các course (quy ra lại theo chữ cái) +select + course_id, + course_name, + avg(score) as average_score, + ( + case + when avg(score) >= 9 then "A" + when avg(score) >= 8 then "B" + when avg(score) >= 6 then "C" + when avg(score) >= 4 then "D" + when avg(score) >= 2 then "E" + else "F" + end + ) as average_grade +from + Enroll_Grade + join Class using (class_id) + join Course using (course_id) +group by + course_id; \ No newline at end of file