diff --git a/tp1-university-system/tp1-solution b/tp1-university-system/tp1-solution new file mode 100644 index 0000000..5d39332 --- /dev/null +++ b/tp1-university-system/tp1-solution @@ -0,0 +1,490 @@ +/* ============================================================ + TP1 - University Management System + File: tp1_solutions.sql + DB: MySQL 8+ + ============================================================ */ + +DROP DATABASE IF EXISTS university_db; +CREATE DATABASE university_db; +USE university_db; + +/* ============================================================ + 1) TABLE: departments + ============================================================ */ +CREATE TABLE departments ( + department_id INT PRIMARY KEY AUTO_INCREMENT, + department_name VARCHAR(100) NOT NULL, + building VARCHAR(50), + budget DECIMAL(12,2), + department_head VARCHAR(100), + creation_date DATE +); + +/* ============================================================ + 2) TABLE: professors + ============================================================ */ +CREATE TABLE professors ( + professor_id INT PRIMARY KEY AUTO_INCREMENT, + last_name VARCHAR(50) NOT NULL, + first_name VARCHAR(50) NOT NULL, + email VARCHAR(100) NOT NULL UNIQUE, + phone VARCHAR(20), + department_id INT NULL, + hire_date DATE, + salary DECIMAL(10,2), + specialization VARCHAR(100), + CONSTRAINT fk_prof_department + FOREIGN KEY (department_id) REFERENCES departments(department_id) + ON DELETE SET NULL + ON UPDATE CASCADE +); + +/* ============================================================ + 3) TABLE: students + ============================================================ */ +CREATE TABLE students ( + student_id INT PRIMARY KEY AUTO_INCREMENT, + student_number VARCHAR(20) NOT NULL UNIQUE, + last_name VARCHAR(50) NOT NULL, + first_name VARCHAR(50) NOT NULL, + date_of_birth DATE, + email VARCHAR(100) NOT NULL UNIQUE, + phone VARCHAR(20), + address TEXT, + department_id INT NULL, + level VARCHAR(20) NOT NULL, + enrollment_date DATE DEFAULT (CURRENT_DATE), + CONSTRAINT chk_students_level + CHECK (level IN ('L1','L2','L3','M1','M2')), + CONSTRAINT fk_student_department + FOREIGN KEY (department_id) REFERENCES departments(department_id) + ON DELETE SET NULL + ON UPDATE CASCADE +); + +/* ============================================================ + 4) TABLE: courses + ============================================================ */ +CREATE TABLE courses ( + course_id INT PRIMARY KEY AUTO_INCREMENT, + course_code VARCHAR(10) NOT NULL UNIQUE, + course_name VARCHAR(150) NOT NULL, + description TEXT, + credits INT NOT NULL, + semester INT NOT NULL, + department_id INT NOT NULL, + professor_id INT NULL, + max_capacity INT DEFAULT 30, + CONSTRAINT chk_courses_credits CHECK (credits > 0), + CONSTRAINT chk_courses_semester CHECK (semester IN (1,2)), + CONSTRAINT fk_course_department + FOREIGN KEY (department_id) REFERENCES departments(department_id) + ON DELETE CASCADE + ON UPDATE CASCADE, + CONSTRAINT fk_course_professor + FOREIGN KEY (professor_id) REFERENCES professors(professor_id) + ON DELETE SET NULL + ON UPDATE CASCADE +); + +/* ============================================================ + 5) TABLE: enrollments + ============================================================ */ +CREATE TABLE enrollments ( + enrollment_id INT PRIMARY KEY AUTO_INCREMENT, + student_id INT NOT NULL, + course_id INT NOT NULL, + enrollment_date DATE DEFAULT (CURRENT_DATE), + academic_year VARCHAR(9) NOT NULL, + status VARCHAR(20) DEFAULT 'In Progress', + CONSTRAINT chk_enroll_status + CHECK (status IN ('In Progress','Passed','Failed','Dropped')), + CONSTRAINT chk_academic_year_format + CHECK (academic_year REGEXP '^[0-9]{4}-[0-9]{4}$'), + CONSTRAINT fk_enroll_student + FOREIGN KEY (student_id) REFERENCES students(student_id) + ON DELETE CASCADE + ON UPDATE CASCADE, + CONSTRAINT fk_enroll_course + FOREIGN KEY (course_id) REFERENCES courses(course_id) + ON DELETE CASCADE + ON UPDATE CASCADE, + CONSTRAINT uq_student_course_year UNIQUE (student_id, course_id, academic_year) +); + +/* ============================================================ + 6) TABLE: grades + ============================================================ */ +CREATE TABLE grades ( + grade_id INT PRIMARY KEY AUTO_INCREMENT, + enrollment_id INT NOT NULL, + evaluation_type VARCHAR(30) NOT NULL, + grade DECIMAL(5,2) NOT NULL, + coefficient DECIMAL(3,2) DEFAULT 1.00, + evaluation_date DATE, + comments TEXT, + CONSTRAINT chk_eval_type + CHECK (evaluation_type IN ('Assignment','Lab','Exam','Project')), + CONSTRAINT chk_grade_range + CHECK (grade >= 0 AND grade <= 20), + CONSTRAINT fk_grade_enrollment + FOREIGN KEY (enrollment_id) REFERENCES enrollments(enrollment_id) + ON DELETE CASCADE + ON UPDATE CASCADE +); + +/* ============================================================ + REQUIRED INDEXES + ============================================================ */ +CREATE INDEX idx_student_department ON students(department_id); +CREATE INDEX idx_course_professor ON courses(professor_id); +CREATE INDEX idx_enrollment_student ON enrollments(student_id); +CREATE INDEX idx_enrollment_course ON enrollments(course_id); +CREATE INDEX idx_grades_enrollment ON grades(enrollment_id); + +/* ============================================================ + TEST DATA INSERTS + ============================================================ */ + +-- Departments (4) +INSERT INTO departments (department_name, building, budget, department_head, creation_date) VALUES +('Computer Science', 'Building A', 500000.00, 'Dr. Alan Turing', '2001-09-01'), +('Mathematics', 'Building B', 350000.00, 'Dr. Emmy Noether', '1998-10-15'), +('Physics', 'Building C', 400000.00, 'Dr. Marie Curie', '1995-03-20'), +('Civil Engineering','Building D', 600000.00, 'Dr. Gustave Eiffel', '2005-01-10'); + +-- Professors (6) (>=3 in CS, >=1 in each other dept) +INSERT INTO professors (last_name, first_name, email, phone, department_id, hire_date, salary, specialization) VALUES +('Smith', 'John', 'john.smith@uni.edu', '+213600000001', 1, '2016-09-01', 5200.00, 'Databases'), +('Johnson', 'Emily', 'emily.johnson@uni.edu','+213600000002', 1, '2018-02-15', 4900.00, 'Networks'), +('Brown', 'David', 'david.brown@uni.edu', '+213600000003', 1, '2014-11-10', 6100.00, 'AI'), +('Garcia', 'Sofia', 'sofia.garcia@uni.edu', '+213600000004', 2, '2012-01-20', 5800.00, 'Algebra'), +('Martin', 'Lucas', 'lucas.martin@uni.edu', '+213600000005', 3, '2010-06-05', 6300.00, 'Quantum Physics'), +('Dupont', 'Claire', 'claire.dupont@uni.edu','+213600000006', 4, '2019-09-12', 4700.00, 'Structures'); + +-- Students (8) mix L2/L3/M1 across departments +INSERT INTO students (student_number, last_name, first_name, date_of_birth, email, phone, address, department_id, level, enrollment_date) VALUES +('S2024-001','BoucENNA','Achref','2003-05-14','achref.boucenna@uni.edu','+213700000001','Algiers',1,'L3','2024-09-15'), +('S2024-002','Kaci','Yasmine','2004-02-21','yasmine.kaci@uni.edu','+213700000002','Oran',1,'L2','2024-09-15'), +('S2024-003','Benali','Omar','2003-11-02','omar.benali@uni.edu','+213700000003','Blida',2,'L3','2024-09-15'), +('S2024-004','Saidi','Lina','2002-08-09','lina.saidi@uni.edu','+213700000004','Constantine',3,'M1','2024-09-15'), +('S2024-005','Haddad','Nadir','2004-01-30','nadir.haddad@uni.edu','+213700000005','Setif',4,'L2','2024-09-15'), +('S2023-006','Meziane','Sara','2003-03-18','sara.meziane@uni.edu','+213700000006','Tizi Ouzou',1,'M1','2023-09-15'), +('S2023-007','Bensaid','Ilyes','2002-12-12','ilyes.bensaid@uni.edu','+213700000007','Annaba',2,'M1','2023-09-15'), +('S2024-008','Kerboua','Meriem','2003-07-07','meriem.kerboua@uni.edu','+213700000008','Bejaia',3,'L3','2024-09-15'); + +-- Courses (7) 5-6 credits, different semesters, assigned to professors +INSERT INTO courses (course_code, course_name, description, credits, semester, department_id, professor_id, max_capacity) VALUES +('CS101','Relational Databases','SQL, constraints, normalization',6,1,1,1,40), +('CS102','Computer Networks','TCP/IP, routing, security basics',5,2,1,2,35), +('CS201','Introduction to AI','Search, ML basics',6,2,1,3,30), +('MA101','Linear Algebra','Vectors, matrices, eigenvalues',6,1,2,4,45), +('PH101','Modern Physics','Relativity and quantum intro',5,1,3,5,30), +('CE101','Statics','Forces, equilibrium, structures',6,1,4,6,40), +('CS150','Programming Concepts','OOP, clean code, testing',5,1,1,2,50); + +-- Enrollments (15) mix 2024-2025 and 2023-2024 and statuses +INSERT INTO enrollments (student_id, course_id, enrollment_date, academic_year, status) VALUES +-- 2024-2025 (current) +(1, 1, '2024-10-01','2024-2025','In Progress'), +(1, 2, '2024-10-01','2024-2025','In Progress'), +(1, 3, '2024-10-01','2024-2025','In Progress'), +(2, 1, '2024-10-02','2024-2025','In Progress'), +(2, 7, '2024-10-02','2024-2025','In Progress'), +(3, 4, '2024-10-03','2024-2025','In Progress'), +(4, 5, '2024-10-03','2024-2025','In Progress'), +(5, 6, '2024-10-04','2024-2025','In Progress'), +(8, 5, '2024-10-05','2024-2025','In Progress'), + +-- 2023-2024 (previous) with various statuses +(6, 1, '2023-10-01','2023-2024','Passed'), +(6, 2, '2023-10-01','2023-2024','Passed'), +(6, 3, '2023-10-01','2023-2024','Failed'), +(7, 4, '2023-10-02','2023-2024','Passed'), +(7, 1, '2023-10-02','2023-2024','Dropped'), +(8, 7, '2023-10-03','2023-2024','Passed'); + +-- Grades (12) different eval types, coefficients, grades 10-18 +-- NOTE: enrollment_id values are auto-generated in insertion order above (1..15) +INSERT INTO grades (enrollment_id, evaluation_type, grade, coefficient, evaluation_date, comments) VALUES +(10,'Exam', 16.00, 2.00, '2024-01-20','Good exam performance'), +(10,'Project', 15.50, 1.50, '2024-01-10','Solid project'), +(11,'Exam', 14.00, 2.00, '2024-01-22','Good understanding'), +(11,'Lab', 17.00, 1.00, '2023-12-15','Excellent labs'), +(12,'Exam', 10.50, 2.00, '2024-01-25','Needs improvement'), +(12,'Assignment',12.00, 1.00, '2023-12-05','Average assignment'), +(13,'Exam', 18.00, 2.00, '2024-01-18','Excellent'), +(13,'Project', 16.00, 1.00, '2024-01-05','Good project'), +(15,'Exam', 15.00, 2.00, '2024-01-12','Nice'), +(15,'Lab', 14.50, 1.00, '2023-12-01','Consistent'), +(14,'Exam', 11.00, 2.00, '2024-01-14','Dropped later'), +(14,'Assignment',10.00, 1.00, '2023-11-25','Early work'); + +/* ============================================================ + 30 SQL QUERIES (Q1 .. Q30) + Replace/adjust if your queries.sql has different questions. + ============================================================ */ + +-- Q1: List all departments ordered by budget (highest first) +SELECT department_id, department_name, building, budget +FROM departments +ORDER BY budget DESC; + +-- Q2: List all professors with their department name +SELECT p.professor_id, p.last_name, p.first_name, d.department_name +FROM professors p +LEFT JOIN departments d ON d.department_id = p.department_id +ORDER BY d.department_name, p.last_name; + +-- Q3: Count professors per department +SELECT d.department_name, COUNT(p.professor_id) AS professor_count +FROM departments d +LEFT JOIN professors p ON p.department_id = d.department_id +GROUP BY d.department_id, d.department_name +ORDER BY professor_count DESC; + +-- Q4: List students with department + level +SELECT s.student_number, s.last_name, s.first_name, s.level, d.department_name +FROM students s +LEFT JOIN departments d ON d.department_id = s.department_id +ORDER BY d.department_name, s.level, s.last_name; + +-- Q5: Count students per level +SELECT level, COUNT(*) AS nb_students +FROM students +GROUP BY level +ORDER BY level; + +-- Q6: List all courses with department + professor +SELECT c.course_code, c.course_name, c.credits, c.semester, + d.department_name, + CONCAT(p.first_name,' ',p.last_name) AS professor +FROM courses c +JOIN departments d ON d.department_id = c.department_id +LEFT JOIN professors p ON p.professor_id = c.professor_id +ORDER BY c.semester, c.course_code; + +-- Q7: Courses that have no assigned professor +SELECT course_code, course_name +FROM courses +WHERE professor_id IS NULL; + +-- Q8: Number of courses per department +SELECT d.department_name, COUNT(c.course_id) AS course_count +FROM departments d +LEFT JOIN courses c ON c.department_id = d.department_id +GROUP BY d.department_id, d.department_name +ORDER BY course_count DESC; + +-- Q9: List enrollments (student + course + year + status) +SELECT e.enrollment_id, + s.student_number, + CONCAT(s.first_name,' ',s.last_name) AS student, + c.course_code, + c.course_name, + e.academic_year, + e.status +FROM enrollments e +JOIN students s ON s.student_id = e.student_id +JOIN courses c ON c.course_id = e.course_id +ORDER BY e.academic_year DESC, s.student_number, c.course_code; + +-- Q10: Count enrollments per academic year +SELECT academic_year, COUNT(*) AS total_enrollments +FROM enrollments +GROUP BY academic_year +ORDER BY academic_year DESC; + +-- Q11: Students enrolled in more than 2 courses in 2024-2025 +SELECT s.student_number, CONCAT(s.first_name,' ',s.last_name) AS student, + COUNT(*) AS nb_courses +FROM enrollments e +JOIN students s ON s.student_id = e.student_id +WHERE e.academic_year = '2024-2025' +GROUP BY s.student_id, s.student_number, student +HAVING COUNT(*) > 2 +ORDER BY nb_courses DESC; + +-- Q12: For each course (2024-2025), count enrolled students +SELECT c.course_code, c.course_name, COUNT(e.enrollment_id) AS enrolled +FROM courses c +LEFT JOIN enrollments e + ON e.course_id = c.course_id AND e.academic_year = '2024-2025' +GROUP BY c.course_id, c.course_code, c.course_name +ORDER BY enrolled DESC, c.course_code; + +-- Q13: Courses that exceed or reach 80% capacity (2024-2025) +SELECT c.course_code, c.course_name, c.max_capacity, + COUNT(e.enrollment_id) AS enrolled, + ROUND(100 * COUNT(e.enrollment_id) / c.max_capacity, 2) AS pct_full +FROM courses c +LEFT JOIN enrollments e + ON e.course_id = c.course_id AND e.academic_year = '2024-2025' +GROUP BY c.course_id, c.course_code, c.course_name, c.max_capacity +HAVING (COUNT(e.enrollment_id) / c.max_capacity) >= 0.80 +ORDER BY pct_full DESC; + +-- Q14: List grades with student + course + evaluation info +SELECT g.grade_id, s.student_number, c.course_code, g.evaluation_type, + g.grade, g.coefficient, g.evaluation_date +FROM grades g +JOIN enrollments e ON e.enrollment_id = g.enrollment_id +JOIN students s ON s.student_id = e.student_id +JOIN courses c ON c.course_id = e.course_id +ORDER BY g.evaluation_date DESC, s.student_number; + +-- Q15: Weighted average grade per enrollment +SELECT e.enrollment_id, + s.student_number, + c.course_code, + ROUND(SUM(g.grade * g.coefficient) / NULLIF(SUM(g.coefficient),0), 2) AS weighted_avg +FROM enrollments e +JOIN students s ON s.student_id = e.student_id +JOIN courses c ON c.course_id = e.course_id +LEFT JOIN grades g ON g.enrollment_id = e.enrollment_id +GROUP BY e.enrollment_id, s.student_number, c.course_code +ORDER BY weighted_avg DESC; + +-- Q16: Students with average grade >= 14 (all years, across all their graded enrollments) +SELECT s.student_number, + CONCAT(s.first_name,' ',s.last_name) AS student, + ROUND(SUM(g.grade*g.coefficient)/NULLIF(SUM(g.coefficient),0), 2) AS overall_avg +FROM students s +JOIN enrollments e ON e.student_id = s.student_id +JOIN grades g ON g.enrollment_id = e.enrollment_id +GROUP BY s.student_id, s.student_number, student +HAVING overall_avg >= 14 +ORDER BY overall_avg DESC; + +-- Q17: For each department, average professor salary +SELECT d.department_name, + ROUND(AVG(p.salary), 2) AS avg_salary, + MIN(p.salary) AS min_salary, + MAX(p.salary) AS max_salary +FROM departments d +LEFT JOIN professors p ON p.department_id = d.department_id +GROUP BY d.department_id, d.department_name +ORDER BY avg_salary DESC; + +-- Q18: Professors who teach more than 1 course +SELECT p.professor_id, + CONCAT(p.first_name,' ',p.last_name) AS professor, + COUNT(c.course_id) AS nb_courses +FROM professors p +JOIN courses c ON c.professor_id = p.professor_id +GROUP BY p.professor_id, professor +HAVING nb_courses > 1 +ORDER BY nb_courses DESC; + +-- Q19: List students who have at least one enrollment with status 'Dropped' +SELECT DISTINCT s.student_number, CONCAT(s.first_name,' ',s.last_name) AS student +FROM students s +JOIN enrollments e ON e.student_id = s.student_id +WHERE e.status = 'Dropped' +ORDER BY s.student_number; + +-- Q20: For each academic year, distribution of statuses +SELECT academic_year, status, COUNT(*) AS cnt +FROM enrollments +GROUP BY academic_year, status +ORDER BY academic_year DESC, cnt DESC; + +-- Q21: Top 3 best enrollments by weighted average (only enrollments with grades) +SELECT + e.enrollment_id, + s.student_number, + c.course_code, + ROUND(SUM(g.grade*g.coefficient)/SUM(g.coefficient), 2) AS weighted_avg +FROM enrollments e +JOIN students s ON s.student_id = e.student_id +JOIN courses c ON c.course_id = e.course_id +JOIN grades g ON g.enrollment_id = e.enrollment_id +GROUP BY e.enrollment_id, s.student_number, c.course_code +ORDER BY weighted_avg DESC +LIMIT 3; + +-- Q22: For each course, average grade (weighted) across all students (based on grades) +SELECT c.course_code, + ROUND(SUM(g.grade*g.coefficient)/NULLIF(SUM(g.coefficient),0), 2) AS course_avg +FROM courses c +JOIN enrollments e ON e.course_id = c.course_id +JOIN grades g ON g.enrollment_id = e.enrollment_id +GROUP BY c.course_id, c.course_code +ORDER BY course_avg DESC; + +-- Q23: Students not enrolled in any course in 2024-2025 +SELECT s.student_number, CONCAT(s.first_name,' ',s.last_name) AS student +FROM students s +LEFT JOIN enrollments e + ON e.student_id = s.student_id AND e.academic_year = '2024-2025' +WHERE e.enrollment_id IS NULL +ORDER BY s.student_number; + +-- Q24: Courses with zero enrollments in 2024-2025 +SELECT c.course_code, c.course_name +FROM courses c +LEFT JOIN enrollments e + ON e.course_id = c.course_id AND e.academic_year = '2024-2025' +WHERE e.enrollment_id IS NULL +ORDER BY c.course_code; + +-- Q25: Students with at least 2 enrollments in 2023-2024 +SELECT s.student_number, CONCAT(s.first_name,' ',s.last_name) AS student, COUNT(*) AS nb +FROM students s +JOIN enrollments e ON e.student_id = s.student_id +WHERE e.academic_year = '2023-2024' +GROUP BY s.student_id, s.student_number, student +HAVING nb >= 2 +ORDER BY nb DESC; + +-- Q26: For each student, number of passed courses (all years) +SELECT s.student_number, + CONCAT(s.first_name,' ',s.last_name) AS student, + SUM(CASE WHEN e.status = 'Passed' THEN 1 ELSE 0 END) AS passed_count +FROM students s +LEFT JOIN enrollments e ON e.student_id = s.student_id +GROUP BY s.student_id, s.student_number, student +ORDER BY passed_count DESC; + +-- Q27: For each department, count students and professors +SELECT d.department_name, + COUNT(DISTINCT s.student_id) AS nb_students, + COUNT(DISTINCT p.professor_id) AS nb_professors +FROM departments d +LEFT JOIN students s ON s.department_id = d.department_id +LEFT JOIN professors p ON p.department_id = d.department_id +GROUP BY d.department_id, d.department_name +ORDER BY nb_students DESC, nb_professors DESC; + +-- Q28: List students with their total enrolled credits for 2024-2025 (only In Progress) +SELECT s.student_number, + CONCAT(s.first_name,' ',s.last_name) AS student, + COALESCE(SUM(c.credits),0) AS total_credits +FROM students s +LEFT JOIN enrollments e + ON e.student_id = s.student_id + AND e.academic_year = '2024-2025' + AND e.status = 'In Progress' +LEFT JOIN courses c ON c.course_id = e.course_id +GROUP BY s.student_id, s.student_number, student +ORDER BY total_credits DESC; + +-- Q29: Rank students by overall weighted average (based on all their grades) +SELECT + s.student_number, + CONCAT(s.first_name,' ',s.last_name) AS student, + ROUND(SUM(g.grade*g.coefficient)/NULLIF(SUM(g.coefficient),0), 2) AS overall_avg, + DENSE_RANK() OVER ( + ORDER BY SUM(g.grade*g.coefficient)/NULLIF(SUM(g.coefficient),0) DESC + ) AS rank_pos +FROM students s +JOIN enrollments e ON e.student_id = s.student_id +JOIN grades g ON g.enrollment_id = e.enrollment_id +GROUP BY s.student_id, s.student_number, student +ORDER BY rank_pos, s.student_number; + +-- Q30: Find the department with the highest total budget (single row) +SELECT department_id, department_name, budget +FROM departments +ORDER BY budget DESC +LIMIT 1; diff --git a/tp2-hospital-system/tp2_solutions.sql b/tp2-hospital-system/tp2_solutions.sql new file mode 100644 index 0000000..153c093 --- /dev/null +++ b/tp2-hospital-system/tp2_solutions.sql @@ -0,0 +1,216 @@ +-- ============================================ +-- tp2_solutions.sql +-- TP2: Hospital Management System (MySQL 8+) +-- ============================================ + +/* ========== 0) DATABASE CREATION ========== */ +DROP DATABASE IF EXISTS hospital_management_tp2; +CREATE DATABASE hospital_management_tp2 + CHARACTER SET utf8mb4 + COLLATE utf8mb4_unicode_ci; +USE hospital_management_tp2; + +/* ========== 1) TABLES ========== */ + +-- 1) specialties +CREATE TABLE specialties ( + specialty_id INT PRIMARY KEY AUTO_INCREMENT, + specialty_name VARCHAR(100) NOT NULL UNIQUE, + description TEXT, + consultation_fee DECIMAL(10,2) NOT NULL +); + +-- 2) doctors +CREATE TABLE doctors ( + doctor_id INT PRIMARY KEY AUTO_INCREMENT, + last_name VARCHAR(50) NOT NULL, + first_name VARCHAR(50) NOT NULL, + email VARCHAR(100) NOT NULL UNIQUE, + phone VARCHAR(20), + specialty_id INT NOT NULL, + license_number VARCHAR(20) NOT NULL UNIQUE, + hire_date DATE, + office VARCHAR(100), + active BOOLEAN DEFAULT TRUE, + CONSTRAINT fk_doctors_specialty + FOREIGN KEY (specialty_id) + REFERENCES specialties(specialty_id) + ON DELETE RESTRICT + ON UPDATE CASCADE +); + +-- 3) patients +CREATE TABLE patients ( + patient_id INT PRIMARY KEY AUTO_INCREMENT, + file_number VARCHAR(20) NOT NULL UNIQUE, + last_name VARCHAR(50) NOT NULL, + first_name VARCHAR(50) NOT NULL, + date_of_birth DATE NOT NULL, + gender ENUM('M','F') NOT NULL, + blood_type VARCHAR(5), + email VARCHAR(100), + phone VARCHAR(20) NOT NULL, + address TEXT, + city VARCHAR(50), + province VARCHAR(50), + registration_date DATE DEFAULT (CURRENT_DATE), + insurance VARCHAR(100), + insurance_number VARCHAR(50), + allergies TEXT, + medical_history TEXT +); + +-- 4) consultations +CREATE TABLE consultations ( + consultation_id INT PRIMARY KEY AUTO_INCREMENT, + patient_id INT NOT NULL, + doctor_id INT NOT NULL, + consultation_date DATETIME NOT NULL, + reason TEXT NOT NULL, + diagnosis TEXT, + observations TEXT, + blood_pressure VARCHAR(20), + temperature DECIMAL(4,2), + weight DECIMAL(5,2), + height DECIMAL(5,2), + status ENUM('Scheduled','In Progress','Completed','Cancelled') DEFAULT 'Scheduled', + amount DECIMAL(10,2), + paid BOOLEAN DEFAULT FALSE, + CONSTRAINT fk_consultations_patient + FOREIGN KEY (patient_id) + REFERENCES patients(patient_id) + ON DELETE RESTRICT + ON UPDATE CASCADE, + CONSTRAINT fk_consultations_doctor + FOREIGN KEY (doctor_id) + REFERENCES doctors(doctor_id) + ON DELETE RESTRICT + ON UPDATE CASCADE +); + +-- 5) medications +CREATE TABLE medications ( + medication_id INT PRIMARY KEY AUTO_INCREMENT, + medication_code VARCHAR(20) NOT NULL UNIQUE, + commercial_name VARCHAR(150) NOT NULL, + generic_name VARCHAR(150), + form VARCHAR(50), + dosage VARCHAR(50), + manufacturer VARCHAR(100), + unit_price DECIMAL(10,2) NOT NULL, + available_stock INT DEFAULT 0, + minimum_stock INT DEFAULT 10, + expiration_date DATE, + prescription_required BOOLEAN DEFAULT TRUE, + reimbursable BOOLEAN DEFAULT FALSE +); + +-- 6) prescriptions +CREATE TABLE prescriptions ( + prescription_id INT PRIMARY KEY AUTO_INCREMENT, + consultation_id INT NOT NULL, + prescription_date DATETIME DEFAULT CURRENT_TIMESTAMP, + treatment_duration INT, -- days + general_instructions TEXT, + CONSTRAINT fk_prescriptions_consultation + FOREIGN KEY (consultation_id) + REFERENCES consultations(consultation_id) + ON DELETE CASCADE + ON UPDATE CASCADE +); + +-- 7) prescription_details +CREATE TABLE prescription_details ( + detail_id INT PRIMARY KEY AUTO_INCREMENT, + prescription_id INT NOT NULL, + medication_id INT NOT NULL, + quantity INT NOT NULL, + dosage_instructions VARCHAR(200) NOT NULL, + duration INT NOT NULL, -- days + total_price DECIMAL(10,2), + CONSTRAINT chk_quantity_positive CHECK (quantity > 0), + CONSTRAINT fk_details_prescription + FOREIGN KEY (prescription_id) + REFERENCES prescriptions(prescription_id) + ON DELETE CASCADE + ON UPDATE CASCADE, + CONSTRAINT fk_details_medication + FOREIGN KEY (medication_id) + REFERENCES medications(medication_id) + ON DELETE RESTRICT + ON UPDATE CASCADE +); + +/* ========== 2) REQUIRED INDEXES ========== */ +CREATE INDEX idx_patients_name ON patients(last_name, first_name); +CREATE INDEX idx_consultations_date ON consultations(consultation_date); +CREATE INDEX idx_consultations_patient ON consultations(patient_id); +CREATE INDEX idx_consultations_doctor ON consultations(doctor_id); +CREATE INDEX idx_medications_commercial_name ON medications(commercial_name); +CREATE INDEX idx_prescriptions_consultation ON prescriptions(consultation_id); + +/* ========== 3) TEST DATA INSERTS ========== */ + +-- Specialties (6) +INSERT INTO specialties (specialty_name, description, consultation_fee) VALUES +('General Medicine', 'Primary care and general health assessment.', 2000.00), +('Cardiology', 'Heart and cardiovascular system care.', 3500.00), +('Pediatrics', 'Medical care for infants, children, and adolescents.', 2500.00), +('Dermatology', 'Skin, hair, and nail conditions.', 3000.00), +('Orthopedics', 'Bones, joints, ligaments, and muscles.', 3200.00), +('Gynecology', 'Women reproductive health and prenatal care.', 3300.00); + +-- Doctors (6) one per specialty +INSERT INTO doctors (last_name, first_name, email, phone, specialty_id, license_number, hire_date, office, active) VALUES +('Benali', 'Sami', 'sami.benali@hospital.dz', '0550-100-101', 1, 'LIC-GM-1001', '2021-03-15', 'Bldg A - Room 101', TRUE), +('Khelifi', 'Nadia', 'nadia.khelifi@hospital.dz','0550-100-102', 2, 'LIC-CAR-2001','2020-06-01', 'Bldg B - Room 210', TRUE), +('Mahmoudi', 'Yanis', 'yanis.mahmoudi@hospital.dz','0550-100-103',3, 'LIC-PED-3001','2022-01-10', 'Bldg C - Room 305', TRUE), +('Ait', 'Lina', 'lina.ait@hospital.dz', '0550-100-104', 4, 'LIC-DER-4001','2019-09-20', 'Bldg D - Room 402', TRUE), +('Bouaziz', 'Karim', 'karim.bouaziz@hospital.dz','0550-100-105', 5, 'LIC-ORT-5001','2018-11-05', 'Bldg E - Room 115', TRUE), +('Saadi', 'Meriem', 'meriem.saadi@hospital.dz', '0550-100-106', 6, 'LIC-GYN-6001','2023-04-12', 'Bldg F - Room 220', TRUE); + +-- Patients (8) various ages, blood types, allergies, insurance mix +INSERT INTO patients +(file_number,last_name,first_name,date_of_birth,gender,blood_type,email,phone,address,city,province,registration_date,insurance,insurance_number,allergies,medical_history) +VALUES +('FN-0001','Boukacem','Amine','2015-05-09','M','O+','amine.boukacem@mail.dz','0770-200-201','Cité 120 Logts','Algiers','Algiers','2024-12-10','CNAS','CNAS-778812','Peanuts','Asthma (mild)'), +('FN-0002','Haddad','Sara','1999-08-22','F','A+','sara.haddad@mail.dz','0770-200-202','Rue Didouche Mourad','Algiers','Algiers','2025-01-05',NULL,NULL,NULL,'No major history'), +('FN-0003','Ziani','Rachid','1978-02-14','M','B+','rachid.ziani@mail.dz','0770-200-203','Lotissement El Biar','Algiers','Algiers','2025-02-01','CNAS','CNAS-551100','Penicillin','Hypertension'), +('FN-0004','Toumi','Ines','2008-11-30','F','AB+','ines.toumi@mail.dz','0770-200-204','Hai 5 Juillet','Blida','Blida','2025-01-20','Private','PRV-204455','Dust','Eczema'), +('FN-0005','Bensaid','Kamel','1962-04-03','M','A-','kamel.bensaid@mail.dz','0770-200-205','Centre Ville','Oran','Oran','2024-10-18','CNAS','CNAS-900211',NULL,'Type 2 Diabetes'), +('FN-0006','Cherif','Aya','1987-07-17','F','O-','aya.cherif@mail.dz','0770-200-206','Nouvelle Ville','Constantine','Constantine','2025-01-11',NULL,NULL,'Latex','Migraine'), +('FN-0007','Mokhtar','Nour','1950-01-26','F','B-','nour.mokhtar@mail.dz','0770-200-207','Rue Emir Abdelkader','Setif','Setif','2024-09-02','Private','PRV-990012','Shellfish','Cardiac arrhythmia'), +('FN-0008','Larbi','Oussama','2003-03-02','M','O+','oussama.larbi@mail.dz','0770-200-208','Cité Universitaire','Tizi Ouzou','Tizi Ouzou','2025-02-10','CNAS','CNAS-112233',NULL,'Sports injury (knee, 2022)'); + +-- Consultations (8) mix completed/scheduled, dates, paid/unpaid, vitals +-- Note: amount set to match (or close to) specialty fee for realism +INSERT INTO consultations +(patient_id,doctor_id,consultation_date,reason,diagnosis,observations,blood_pressure,temperature,weight,height,status,amount,paid) +VALUES +(1,3,'2025-01-06 10:30:00','Fever and cough','Viral infection','Hydration advised','100/65',38.20,28.50,1.25,'Completed',2500.00,TRUE), +(2,1,'2025-01-18 09:00:00','General checkup',NULL,'Routine screening','110/70',36.70,58.00,1.64,'Completed',2000.00,FALSE), +(3,2,'2025-02-12 14:15:00','Chest discomfort','Possible angina','ECG recommended','145/90',37.10,82.30,1.72,'Completed',3500.00,TRUE), +(4,4,'2025-01-28 16:00:00','Skin rash','Dermatitis','Avoid allergens','105/68',36.90,44.20,1.50,'Completed',3000.00,FALSE), +(5,1,'2025-03-05 11:00:00','Fatigue and high glucose','Diabetes follow-up','Adjust diet','130/85',36.60,90.10,1.70,'Completed',2000.00,TRUE), +(6,6,'2025-02-20 13:30:00','Prenatal visit','Normal','Ultrasound scheduled','112/72',36.80,63.40,1.66,'Completed',3300.00,FALSE), +(7,2,'2025-04-10 08:45:00','Palpitations','Arrhythmia follow-up','Holter monitoring','150/95',36.90,70.00,1.60,'Scheduled',3500.00,FALSE), +(8,5,'2025-01-10 15:20:00','Knee pain','Ligament strain','Physiotherapy advised','120/75',36.70,75.50,1.78,'Completed',3200.00,TRUE); + +-- Medications (10) prices/stock/forms/expirations +INSERT INTO medications +(medication_code,commercial_name,generic_name,form,dosage,manufacturer,unit_price,available_stock,minimum_stock,expiration_date,prescription_required,reimbursable) +VALUES +('MED-001','Paracetal 500','Paracetamol','Tablet','500mg','DZ Pharma',120.00,200,50,'2027-01-15',FALSE,TRUE), +('MED-002','AmoxiCaps','Amoxicillin','Capsule','500mg','MedAlger',380.00,25,40,'2026-07-01',TRUE,TRUE), +('MED-003','CoughStop','Dextromethorphan','Syrup','15mg/5ml','Saha Lab',450.00,12,20,'2026-05-20',FALSE,FALSE), +('MED-004','CardioPlus','Aspirin','Tablet','100mg','HeartCare',300.00,80,30,'2028-09-10',TRUE,TRUE), +('MED-005','Dermacort','Hydrocortisone','Cream','1%','DermaCo',600.00,8,15,'2026-04-30',TRUE,FALSE), +('MED-006','InsuControl','Metformin','Tablet','850mg','Glucare',520.00,60,40,'2027-11-05',TRUE,TRUE), +('MED-007','OrthoGel','Diclofenac','Gel','1%','OrthoMed',700.00,5,10,'2026-06-15',FALSE,FALSE), +('MED-008','PrenatalVit','Multivitamins','Tablet','Daily','VitaLab',480.00,100,30,'2027-03-01',FALSE,TRUE), +('MED-009','AntiAller','Cetirizine','Tablet','10mg','AllerFree',260.00,9,20,'2026-03-10',FALSE,TRUE), +('MED-010','ThermoScan','Ibuprofen','Tablet','400mg','DZ Pharma',220.00,150,40,'2027-08-18',FALSE,TRUE); + +-- Prescriptions (7) linked to consultations +-- Linked to consultation_id: 1,2,3,4,5,6,8 (no prescription for con_ +