From 0d75a555f4310141b9763de078358dd58f17d7dd Mon Sep 17 00:00:00 2001 From: igorfourier Date: Sat, 16 May 2026 10:04:36 +0200 Subject: [PATCH] commit sql --- .gitignore | 184 +++++++++++++++++++++++++++++++++ exercise1_blog_database.sql | 76 ++++++++++++++ exercise2_airline_database.sql | 155 +++++++++++++++++++++++++++ exercise3_queries.sql | 177 +++++++++++++++++++++++++++++++ 4 files changed, 592 insertions(+) create mode 100644 .gitignore create mode 100644 exercise1_blog_database.sql create mode 100644 exercise2_airline_database.sql create mode 100644 exercise3_queries.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7a6db6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,184 @@ +# ================================================================ +# .gitignore for SQL Lab Project +# ================================================================ + +# ================================================================ +# IDE and Editor Files +# ================================================================ + +# IntelliJ IDEA +.idea/ +*.iml +*.iws +*.ipr +out/ + +# Visual Studio Code +.vscode/ +*.code-workspace + +# Sublime Text +*.sublime-project +*.sublime-workspace + +# Eclipse +.project +.metadata +.classpath +.settings/ + +# NetBeans +nbproject/ +build/ +nbbuild/ +dist/ +nbdist/ + +# ================================================================ +# Operating System Files +# ================================================================ + +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* +.Spotlight-V100 +.Trashes + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# Linux +*~ +.directory + +# ================================================================ +# Database Files +# ================================================================ + +# MySQL +*.sql~ +*.sql.bak +*.sql.backup +mysql-data/ +mysql-bin/ + +# SQLite +*.db +*.sqlite +*.sqlite3 + +# PostgreSQL +*.pgsql +*.dump + +# Database backup files +*.backup +*.bak +*.old + +# ================================================================ +# Temporary and Log Files +# ================================================================ + +# Logs +*.log +logs/ +*.log.* + +# Temporary files +*.tmp +*.temp +*~ +*.swp +*.swo +.*.swp + +# Cache +*.cache +cache/ + +# ================================================================ +# Project Specific +# ================================================================ + +# Don't ignore the actual SQL solution files +!exercise1_blog_database.sql +!exercise2_airline_database.sql +!exercise3_queries.sql +!SOLUTION_DOCUMENTATION.sql + +# Local database configuration files (if any) +db-config.local.sql +credentials.sql +local-settings.sql + +# Environment files +.env +.env.local +.env.*.local + +# ================================================================ +# Archives and Compressed Files +# ================================================================ + +# Compressed files (exclude if not needed) +*.zip +*.tar +*.tar.gz +*.rar +*.7z + +# ================================================================ +# Node.js (if used for any tooling) +# ================================================================ + +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +yarn.lock + +# ================================================================ +# Java (if used for any tooling) +# ================================================================ + +*.class +*.jar +*.war +*.ear +target/ + +# ================================================================ +# Documentation Build Output +# ================================================================ + +# PDF outputs (if generating documentation) +*.pdf + +# HTML generated docs (keep markdown sources) +docs/_build/ +site/ + +# ================================================================ +# Test and Coverage Reports +# ================================================================ + +coverage/ +*.cover +.coverage +htmlcov/ + +# ================================================================ +# Git Attributes +# ================================================================ + +# Don't ignore .gitignore itself +!.gitignore +!.gitattributes + diff --git a/exercise1_blog_database.sql b/exercise1_blog_database.sql new file mode 100644 index 0000000..ccc00f2 --- /dev/null +++ b/exercise1_blog_database.sql @@ -0,0 +1,76 @@ +-- ================================================================ +-- Exercise 1: Normalize a Blog Database +-- ================================================================ + +-- Step 1: Normalization to 3NF +-- Original table had redundancy with author names repeated +-- Normalized into: +-- - authors table (stores unique authors) +-- - posts table (stores posts with FK to authors) + +-- ================================================================ +-- Step 2: DDL - CREATE TABLE statements +-- ================================================================ + +CREATE TABLE authors ( + author_id INT PRIMARY KEY AUTO_INCREMENT, + author_name VARCHAR(100) NOT NULL UNIQUE +); + +CREATE TABLE posts ( + post_id INT PRIMARY KEY AUTO_INCREMENT, + author_id INT NOT NULL, + title VARCHAR(255) NOT NULL, + word_count INT NOT NULL CHECK (word_count > 0), + views INT DEFAULT 0 CHECK (views >= 0), + FOREIGN KEY (author_id) REFERENCES authors(author_id) +); + +-- Add index for performance on frequent queries +CREATE INDEX idx_posts_author ON posts(author_id); +CREATE INDEX idx_posts_views ON posts(views); + +-- ================================================================ +-- Step 3: INSERT sample data +-- ================================================================ + +-- Insert authors first (referenced table) +INSERT INTO authors (author_name) VALUES +('Maria Charlotte'), +('Juan Perez'), +('Gemma Alcocer'); + +-- Insert posts +INSERT INTO posts (author_id, title, word_count, views) VALUES +(1, 'Best Paint Colors', 814, 14), +(2, 'Small Space Decorating Tips', 1146, 221), +(1, 'Hot Accessories', 986, 105), +(1, 'Mixing Textures', 765, 22), +(2, 'Kitchen Refresh', 1242, 307), +(1, 'Homemade Art Hacks', 1002, 193), +(3, 'Refinishing Wood Floors', 1571, 7542); + +-- ================================================================ +-- Verification Queries +-- ================================================================ + +-- View all data +SELECT + a.author_name, + p.title, + p.word_count, + p.views +FROM posts p +JOIN authors a ON p.author_id = a.author_id +ORDER BY p.post_id; + +-- Total posts per author +SELECT + a.author_name, + COUNT(*) as total_posts, + SUM(p.views) as total_views +FROM posts p +JOIN authors a ON p.author_id = a.author_id +GROUP BY a.author_name +ORDER BY total_views DESC; + diff --git a/exercise2_airline_database.sql b/exercise2_airline_database.sql new file mode 100644 index 0000000..20732a7 --- /dev/null +++ b/exercise2_airline_database.sql @@ -0,0 +1,155 @@ +-- ================================================================ +-- Exercise 2: Normalize an Airline Database +-- ================================================================ + +-- Step 1: Normalization to 3NF +-- Original table had multiple redundancies: +-- - Customer information repeated for each booking +-- - Aircraft information repeated for each flight +-- - Flight information repeated for each booking +-- +-- Normalized into 4 tables: +-- - customers (stores customer info and total mileage) +-- - aircrafts (stores aircraft models and seat capacity) +-- - flights (stores flight routes with FK to aircraft) +-- - bookings (junction table linking customers to flights) + +-- ================================================================ +-- Step 2: Functional Dependencies +-- ================================================================ +-- Customer Name -> Customer Status, Total Customer Mileage +-- Aircraft -> Total Aircraft Seats +-- Flight Number -> Aircraft, Flight Mileage +-- Customer Name + Flight Number -> Booking (many-to-many relationship) + +-- ================================================================ +-- Step 3: DDL - CREATE TABLE statements with FOREIGN KEY constraints +-- ================================================================ + +CREATE TABLE customers ( + customer_id INT PRIMARY KEY AUTO_INCREMENT, + customer_name VARCHAR(100) NOT NULL, + status VARCHAR(20) CHECK (status IN ('Gold', 'Silver', 'None')), + total_mileage INT DEFAULT 0 CHECK (total_mileage >= 0), + UNIQUE(customer_name) +); + +CREATE TABLE aircrafts ( + aircraft_id INT PRIMARY KEY AUTO_INCREMENT, + aircraft_name VARCHAR(50) NOT NULL UNIQUE, + total_seats INT NOT NULL CHECK (total_seats > 0) +); + +CREATE TABLE flights ( + flight_number VARCHAR(10) PRIMARY KEY, + aircraft_id INT NOT NULL, + mileage INT NOT NULL CHECK (mileage > 0), + FOREIGN KEY (aircraft_id) REFERENCES aircrafts(aircraft_id) +); + +CREATE TABLE bookings ( + booking_id INT PRIMARY KEY AUTO_INCREMENT, + customer_id INT NOT NULL, + flight_number VARCHAR(10) NOT NULL, + FOREIGN KEY (customer_id) REFERENCES customers(customer_id), + FOREIGN KEY (flight_number) REFERENCES flights(flight_number) +); + +-- ================================================================ +-- Extra Challenge: Add indexes for performance improvement +-- ================================================================ +CREATE INDEX idx_customer_status ON customers(status); +CREATE INDEX idx_bookings_customer ON bookings(customer_id); +CREATE INDEX idx_bookings_flight ON bookings(flight_number); +CREATE INDEX idx_flights_aircraft ON flights(aircraft_id); + +-- ================================================================ +-- Step 4: INSERT sample data +-- ================================================================ + +-- Insert customers (independent table) +INSERT INTO customers (customer_name, status, total_mileage) VALUES +('Agustine Riviera', 'Silver', 115235), +('Alaina Sepulvida', 'None', 6008), +('Tom Jones', 'Gold', 205767), +('Sam Rio', 'None', 2653), +('Jessica James', 'Silver', 127656), +('Ana Janco', 'Silver', 136773), +('Jennifer Cortez', 'Gold', 300582), +('Christian Janco', 'Silver', 14642); + +-- Insert aircrafts (independent table) +INSERT INTO aircrafts (aircraft_name, total_seats) VALUES +('Boeing 747', 400), +('Airbus A330', 236), +('Boeing 777', 264); + +-- Insert flights (depends on aircrafts) +INSERT INTO flights (flight_number, aircraft_id, mileage) VALUES +('DL143', 1, 135), -- Boeing 747 +('DL122', 2, 4370), -- Airbus A330 +('DL53', 3, 2078), -- Boeing 777 +('DL222', 3, 1765), -- Boeing 777 +('DL37', 1, 531); -- Boeing 747 + +-- Insert bookings (depends on customers and flights) +-- Based on the original data, these are all the bookings: +INSERT INTO bookings (customer_id, flight_number) VALUES +-- Agustine Riviera bookings +(1, 'DL143'), +(1, 'DL122'), +(1, 'DL143'), +(1, 'DL143'), +(1, 'DL143'), +-- Alaina Sepulvida bookings +(2, 'DL122'), +-- Tom Jones bookings +(3, 'DL122'), +(3, 'DL53'), +(3, 'DL222'), +-- Sam Rio bookings +(4, 'DL143'), +(4, 'DL143'), +(4, 'DL37'), +-- Jessica James bookings +(5, 'DL143'), +(5, 'DL122'), +-- Ana Janco bookings +(6, 'DL222'), +-- Jennifer Cortez bookings +(7, 'DL222'), +-- Christian Janco bookings +(8, 'DL222'); + +-- ================================================================ +-- Verification Queries +-- ================================================================ + +-- Recreate original view +SELECT + c.customer_name, + c.status AS customer_status, + f.flight_number, + a.aircraft_name AS aircraft, + a.total_seats AS total_aircraft_seats, + f.mileage AS flight_mileage, + c.total_mileage AS total_customer_mileage +FROM bookings b +JOIN customers c ON b.customer_id = c.customer_id +JOIN flights f ON b.flight_number = f.flight_number +JOIN aircrafts a ON f.aircraft_id = a.aircraft_id +ORDER BY b.booking_id; + +-- Summary statistics +SELECT + COUNT(DISTINCT customer_id) as total_customers, + COUNT(DISTINCT flight_number) as total_flights, + COUNT(DISTINCT aircraft_id) as total_aircrafts, + COUNT(*) as total_bookings +FROM ( + SELECT DISTINCT c.customer_id, f.flight_number, f.aircraft_id + FROM bookings b + JOIN customers c ON b.customer_id = c.customer_id + JOIN flights f ON b.flight_number = f.flight_number +) AS summary; + diff --git a/exercise3_queries.sql b/exercise3_queries.sql new file mode 100644 index 0000000..cbd7606 --- /dev/null +++ b/exercise3_queries.sql @@ -0,0 +1,177 @@ +-- ================================================================ +-- Exercise 3: Write SQL Queries on the Airline Database +-- ================================================================ +-- Prerequisites: Run exercise2_airline_database.sql first to create +-- the schema and insert the sample data. +-- ================================================================ + +-- ================================================================ +-- Query 1: Total number of flights +-- ================================================================ +SELECT COUNT(DISTINCT flight_number) AS total_flights +FROM flights; +-- Expected result: 5 + + +-- ================================================================ +-- Query 2: Average flight distance +-- ================================================================ +SELECT AVG(mileage) AS average_flight_distance +FROM flights; +-- Expected result: 1775.8 + + +-- ================================================================ +-- Query 3: Average number of seats per aircraft +-- ================================================================ +SELECT AVG(total_seats) AS average_seats +FROM aircrafts; +-- Expected result: 300 + + +-- ================================================================ +-- Query 4: Average miles flown by customers, grouped by status +-- ================================================================ +SELECT + status, + AVG(total_mileage) AS average_mileage +FROM customers +GROUP BY status +ORDER BY average_mileage DESC; +-- Expected results: +-- Gold: 253174.5 +-- Silver: 98576.5 +-- None: 4330.5 + + +-- ================================================================ +-- Query 5: Max miles flown by customers, grouped by status +-- ================================================================ +SELECT + status, + MAX(total_mileage) AS max_mileage +FROM customers +GROUP BY status +ORDER BY max_mileage DESC; +-- Expected results: +-- Gold: 300582 +-- Silver: 136773 +-- None: 6008 + + +-- ================================================================ +-- Query 6: Number of aircrafts with "Boeing" in their name +-- ================================================================ +SELECT COUNT(*) AS boeing_count +FROM aircrafts +WHERE aircraft_name LIKE '%Boeing%'; +-- Expected result: 2 + + +-- ================================================================ +-- Query 7: Flights with distance between 300 and 2000 miles +-- ================================================================ +SELECT + flight_number, + aircraft_id, + mileage +FROM flights +WHERE mileage BETWEEN 300 AND 2000 +ORDER BY mileage; +-- Expected results: DL143 (135), DL37 (531), DL222 (1765) + + +-- ================================================================ +-- Query 8: Average flight distance booked, grouped by customer status +-- ================================================================ +SELECT + c.status, + AVG(f.mileage) AS average_booked_distance +FROM bookings b +JOIN customers c ON b.customer_id = c.customer_id +JOIN flights f ON b.flight_number = f.flight_number +GROUP BY c.status +ORDER BY average_booked_distance DESC; +-- This shows the average distance of flights actually booked by customers +-- grouped by their status level + + +-- ================================================================ +-- Query 9: Most booked aircraft among Gold status members +-- ================================================================ +SELECT + a.aircraft_name, + COUNT(*) AS total_bookings +FROM bookings b +JOIN customers c ON b.customer_id = c.customer_id +JOIN flights f ON b.flight_number = f.flight_number +JOIN aircrafts a ON f.aircraft_id = a.aircraft_id +WHERE c.status = 'Gold' +GROUP BY a.aircraft_name +ORDER BY total_bookings DESC +LIMIT 1; +-- Expected result: Boeing 777 (most popular among Gold members) + + +-- ================================================================ +-- BONUS QUERIES: Additional useful analytics +-- ================================================================ + +-- Total bookings per customer +SELECT + c.customer_name, + c.status, + COUNT(*) AS total_bookings, + c.total_mileage +FROM bookings b +JOIN customers c ON b.customer_id = c.customer_id +GROUP BY c.customer_id, c.customer_name, c.status, c.total_mileage +ORDER BY total_bookings DESC; + +-- Most popular flights (by number of bookings) +SELECT + f.flight_number, + a.aircraft_name, + f.mileage, + COUNT(*) AS total_bookings +FROM bookings b +JOIN flights f ON b.flight_number = f.flight_number +JOIN aircrafts a ON f.aircraft_id = a.aircraft_id +GROUP BY f.flight_number, a.aircraft_name, f.mileage +ORDER BY total_bookings DESC; + +-- Aircraft utilization (bookings per aircraft type) +SELECT + a.aircraft_name, + a.total_seats, + COUNT(*) AS total_bookings, + ROUND(COUNT(*) * 100.0 / a.total_seats, 2) AS utilization_percentage +FROM bookings b +JOIN flights f ON b.flight_number = f.flight_number +JOIN aircrafts a ON f.aircraft_id = a.aircraft_id +GROUP BY a.aircraft_id, a.aircraft_name, a.total_seats +ORDER BY total_bookings DESC; + +-- Customer status distribution +SELECT + status, + COUNT(*) AS customer_count, + ROUND(AVG(total_mileage), 2) AS avg_mileage, + SUM(total_mileage) AS total_mileage_all +FROM customers +GROUP BY status +ORDER BY avg_mileage DESC; + +-- Flights by distance range +SELECT + CASE + WHEN mileage < 500 THEN 'Short (< 500 miles)' + WHEN mileage BETWEEN 500 AND 2000 THEN 'Medium (500-2000 miles)' + ELSE 'Long (> 2000 miles)' + END AS distance_category, + COUNT(*) AS flight_count, + AVG(mileage) AS avg_mileage +FROM flights +GROUP BY distance_category +ORDER BY avg_mileage; +