Databases | Tasks for Practical Class 11
Creating an INDEX in SQL
Variant 1: E-commerce Platform
Scenario: You are working on the database for an e-commerce platform. Performance is critical for user experience, especially when searching for products and viewing order histories. You need to add appropriate indexes to optimize common queries.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS OrderItems;
DROP TABLE IF EXISTS Orders;
DROP TABLE IF EXISTS Products;
-- Create the Products table
CREATE TABLE Products (
product_id SERIAL PRIMARY KEY,
sku VARCHAR(50) UNIQUE NOT NULL, -- Stock Keeping Unit
name VARCHAR(200) NOT NULL,
category VARCHAR(100),
price NUMERIC(10, 2) CHECK (price >= 0),
stock_quantity INT DEFAULT 0 CHECK (stock_quantity >= 0),
date_added DATE DEFAULT CURRENT_DATE
);
-- Create the Orders table
CREATE TABLE Orders (
order_id SERIAL PRIMARY KEY,
customer_id INT NOT NULL, -- Assuming a separate Customers table exists elsewhere
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'pending', -- e.g., 'pending', 'processing', 'shipped', 'delivered', 'cancelled'
total_amount NUMERIC(12, 2)
);
-- Create the OrderItems table (linking Orders and Products)
CREATE TABLE OrderItems (
order_item_id SERIAL PRIMARY KEY,
order_id INT NOT NULL REFERENCES Orders(order_id),
product_id INT NOT NULL REFERENCES Products(product_id),
quantity INT NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(10, 2) NOT NULL -- Price at the time of order
);
-- Insert sample data
INSERT INTO Products (sku, name, category, price, stock_quantity, date_added) VALUES
('BK-ADV-01', 'Advanced SQL Guide', 'Books', 49.99, 150, '2023-01-10'),
('EL-LAP-X1', 'UltraSlim Laptop X1', 'Electronics', 1299.00, 50, '2023-02-20'),
('KT-MIX-S2', 'Super Mixer Pro', 'Home Goods', 89.50, 200, '2023-03-15'),
('BK-PYT-BEG', 'Python for Beginners', 'Books', 29.99, 300, '2023-04-01'),
('EL-CAM-Z5', 'Digital Camera Z5', 'Electronics', 450.00, 75, '2023-05-10');
INSERT INTO Orders (customer_id, order_date, status, total_amount) VALUES
(101, '2023-11-01 10:00:00', 'shipped', 179.49),
(102, '2023-11-05 14:30:00', 'processing', 1299.00),
(101, '2023-11-10 09:15:00', 'pending', 79.98),
(103, '2023-11-12 16:45:00', 'delivered', 450.00),
(104, '2023-11-15 11:00:00', 'processing', 89.50);
INSERT INTO OrderItems (order_id, product_id, quantity, unit_price) VALUES
(1, 1, 1, 49.99), (1, 4, 1, 29.99), (1, 3, 1, 89.50), -- Mistake fixed: total matches order 1
(2, 2, 1, 1299.00),
(3, 4, 2, 29.99), (3, 1, 1, 49.99), -- Corrected quantities/prices needed if total should be exactly 79.98. Let's assume order total was an estimate.
(4, 5, 1, 450.00),
(5, 3, 1, 89.50);
Tasks:
- Basic Index: Create an index on the
Products
table to speed up searches based on the productname
. - Foreign Key Index: Create an index on the
Orders
table to quickly find all orders placed by a specificcustomer_id
. - Multicolumn Index: Create a multicolumn index on the
Products
table to optimize queries that filter bycategory
and then sort or filter byprice
. Ensurecategory
is the leading column. - Foreign Key Index (Many-to-Many): Create an index on the
OrderItems
table to efficiently look up items belonging to a specificorder_id
. - Foreign Key Index (Many-to-Many): Create another index on the
OrderItems
table to efficiently find all orders that include a specificproduct_id
. - Reindex Table: Rebuild all indexes currently existing on the
Products
table to optimize their structure after potential data modifications. - Partial Index: Create a partial index on the
Orders
table for theorder_date
column, but only include orders with astatus
of ‘processing’ or ‘pending’. This helps optimize queries looking for active, unshipped orders. - Index on Expression: Create an index on the
Products
table based on the lowercase version of thename
column to facilitate case-insensitive searches. - List Indexes: Use a system catalog query (
pg_indexes
) to list all indexes currently defined for theOrderItems
table. - Drop Index: Remove the expression index created in step 8 (
LOWER(name)
onProducts
).
Variant 2: Library Management System
Scenario: You are designing the database for a library system. Efficient searching for books, authors, and tracking borrowed items is crucial for librarians and patrons. You need to implement indexes to optimize these operations.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS BorrowingRecords;
DROP TABLE IF EXISTS Books;
DROP TABLE IF EXISTS Authors;
-- Create the Authors table
CREATE TABLE Authors (
author_id SERIAL PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100) NOT NULL,
birth_year INT
);
-- Create the Books table
CREATE TABLE Books (
book_id SERIAL PRIMARY KEY,
isbn VARCHAR(17) UNIQUE NOT NULL, -- International Standard Book Number
title VARCHAR(255) NOT NULL,
publication_year INT,
genre VARCHAR(50),
author_id INT REFERENCES Authors(author_id),
copies_available INT DEFAULT 1 CHECK (copies_available >= 0)
);
-- Create the BorrowingRecords table
CREATE TABLE BorrowingRecords (
record_id SERIAL PRIMARY KEY,
book_id INT NOT NULL REFERENCES Books(book_id),
member_id INT NOT NULL, -- Assuming a separate Members table exists elsewhere
borrow_date DATE NOT NULL DEFAULT CURRENT_DATE,
due_date DATE NOT NULL,
return_date DATE -- NULL if not yet returned
);
-- Insert sample data
INSERT INTO Authors (first_name, last_name, birth_year) VALUES
('George', 'Orwell', 1903),
('Jane', 'Austen', 1775),
('Isaac', 'Asimov', 1920),
('J.R.R.', 'Tolkien', 1892);
INSERT INTO Books (isbn, title, publication_year, genre, author_id, copies_available) VALUES
('978-0451524935', 'Nineteen Eighty-Four', 1949, 'Dystopian', 1, 3),
('978-0141439518', 'Pride and Prejudice', 1813, 'Romance', 2, 5),
('978-0553293378', 'Foundation', 1951, 'Science Fiction', 3, 2),
('978-0547928227', 'The Hobbit', 1937, 'Fantasy', 4, 4),
('978-0451524900', 'Animal Farm', 1945, 'Allegory', 1, 3);
INSERT INTO BorrowingRecords (book_id, member_id, borrow_date, due_date, return_date) VALUES
(1, 501, '2024-03-01', '2024-03-15', '2024-03-14'),
(3, 502, '2024-03-05', '2024-03-19', NULL), -- Not returned
(2, 501, '2024-03-10', '2024-03-24', NULL), -- Not returned
(5, 503, '2024-03-12', '2024-03-26', '2024-03-20'),
(1, 502, '2024-03-15', '2024-03-29', NULL); -- Not returned
Tasks:
- Basic Index: Create an index on the
Authors
table to speed up searches based on the author’slast_name
. - Basic Index: Create an index on the
Books
table to allow for faster lookups bytitle
. - Unique Index Explanation: The
Books
table has aUNIQUE
constraint on theisbn
column. Explain the implication this has for indexing this column. - Foreign Key Index: Create an index on the
Books
table to optimize queries joiningBooks
withAuthors
(i.e., index theauthor_id
foreign key). - Multicolumn Index: Create a multicolumn index on the
Books
table to improve performance for queries that search for books within a specificgenre
andpublication_year
.genre
should be the first column in the index. - Foreign Key Index (Tracking Table): Create an index on the
BorrowingRecords
table to quickly find all borrowing records associated with a specificbook_id
. - Foreign Key Index (Tracking Table): Create an index on the
BorrowingRecords
table to quickly find all books borrowed by a specificmember_id
. - Partial Index: Create a partial index on the
BorrowingRecords
table covering thedue_date
column, but only for records where thereturn_date
is NULL. This helps efficiently find overdue books or currently borrowed items. - Index on Expression: Create an index on the
Books
table based on thepublication_year
column, but only storing the decade (e.g., 1950 for 1951, 1810 for 1813). Use integer division or another appropriate expression. This might optimize broad searches by decade.CREATE INDEX idx_books_pub_decade ON Books (((publication_year / 10) * 10));
- List and Drop Index: Use the
\d Books
meta-command (in psql or pgAdmin’s Query Tool SQL pane) to view the indexes on theBooks
table. Then, drop the index ontitle
created in step 2.
Variant 3: Project Management Tool
Scenario: You are the database administrator for a project management application. Users frequently search for projects, filter tasks by status, assignee, and priority, and view task lists. Optimizing these queries with indexes is essential for application responsiveness.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS TaskAssignments; -- Adjusted for clarity
DROP TABLE IF EXISTS Tasks;
DROP TABLE IF EXISTS Projects;
DROP TABLE IF EXISTS Users;
-- Create the Users table
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
full_name VARCHAR(150)
);
-- Create the Projects table
CREATE TABLE Projects (
project_id SERIAL PRIMARY KEY,
project_code VARCHAR(20) UNIQUE NOT NULL, -- e.g., 'ALPHA', 'OMEGA-2'
name VARCHAR(200) NOT NULL,
start_date DATE,
deadline DATE,
status VARCHAR(20) DEFAULT 'planning' -- 'planning', 'active', 'completed', 'on_hold'
);
-- Create the Tasks table
CREATE TABLE Tasks (
task_id SERIAL PRIMARY KEY,
project_id INT NOT NULL REFERENCES Projects(project_id),
title VARCHAR(255) NOT NULL,
description TEXT,
priority INT DEFAULT 3, -- e.g., 1 (High) to 5 (Low)
status VARCHAR(20) DEFAULT 'todo', -- 'todo', 'in_progress', 'review', 'done', 'blocked'
due_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create the TaskAssignments table (linking Tasks and Users)
CREATE TABLE TaskAssignments (
assignment_id SERIAL PRIMARY KEY,
task_id INT NOT NULL REFERENCES Tasks(task_id) ON DELETE CASCADE,
user_id INT NOT NULL REFERENCES Users(user_id),
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (task_id, user_id) -- Ensure a user isn't assigned the same task twice
);
-- Insert sample data
INSERT INTO Users (username, email, full_name) VALUES
('jdoe', 'john.doe@company.com', 'John Doe'),
('asmith', 'alice.smith@company.com', 'Alice Smith'),
('bwhite', 'bob.white@company.com', 'Bob White');
INSERT INTO Projects (project_code, name, start_date, deadline, status) VALUES
('PHOENIX', 'Project Phoenix Rebirth', '2024-01-15', '2024-07-31', 'active'),
('NEBULA', 'Nebula Cloud Migration', '2024-03-01', '2024-12-31', 'planning'),
('TITAN', 'Titan Platform Upgrade', '2023-11-01', '2024-05-31', 'active');
INSERT INTO Tasks (project_id, title, priority, status, due_date) VALUES
(1, 'Define Core Modules', 1, 'done', '2024-02-15'),
(1, 'Develop UI Mockups', 2, 'in_progress', '2024-04-30'),
(1, 'Setup Development Environment', 3, 'todo', '2024-04-10'),
(3, 'Analyze Current Platform', 1, 'in_progress', '2024-04-20'),
(3, 'Draft Upgrade Plan', 2, 'review', '2024-05-05'),
(2, 'Gather Cloud Requirements', 1, 'todo', '2024-04-15');
INSERT INTO TaskAssignments (task_id, user_id) VALUES
(1, 1), -- Task 1 assigned to John Doe
(2, 2), -- Task 2 assigned to Alice Smith
(3, 1), -- Task 3 assigned to John Doe
(4, 3), -- Task 4 assigned to Bob White
(5, 2), -- Task 5 assigned to Alice Smith
(4, 1); -- Task 4 also assigned to John Doe
Tasks:
- Basic Index: Create an index on the
Projects
table to quickly find projects based on theirstatus
. - Unique Index Explanation: The
Users
table hasUNIQUE
constraints onusername
andemail
. What does this mean regarding automatically created indexes on these columns? - Foreign Key Index: Create an index on the
Tasks
table to efficiently retrieve all tasks belonging to a specificproject_id
. - Foreign Key Index (Assignment Table): Create an index on the
TaskAssignments
table to quickly find all assignments (and thus tasks) for a givenuser_id
. - Foreign Key Index (Assignment Table): Create an index on the
TaskAssignments
table to quickly find all assignees for a giventask_id
. - Multicolumn Index: Create a multicolumn index on the
Tasks
table to optimize filtering tasks first byproject_id
and then bystatus
. - Multicolumn Index (Assignments): Create a multicolumn index on
TaskAssignments
table to optimize queries finding tasks assigned to a specific user (user_id
) ordered byassigned_at
timestamp. - Partial Index: Create a partial index on the
Tasks
table covering thedue_date
column, but only for tasks whosestatus
is not ‘done’ or ‘blocked’. This helps find upcoming deadlines for active tasks. - Index on Expression: Create an index on the
Tasks
table based on theUPPER()
function applied to thetitle
column to support case-insensitive title searches. - List and Drop Index: Use the
pg_indexes
system view to list all indexes on theTasks
table. Identify the index created in step 9 (UPPER(title)
) and then drop it.
Variant 4: Online Forum Platform
Scenario: You are responsible for the database performance of a growing online forum. Users need to quickly find posts by topic, author, and search content. Moderators also need efficient ways to review reported posts. Indexing is key to maintaining a good user experience.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Posts;
DROP TABLE IF EXISTS Topics;
DROP TABLE IF EXISTS Users;
-- Create the Users table
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
join_date DATE DEFAULT CURRENT_DATE,
post_count INT DEFAULT 0
);
-- Create the Topics table
CREATE TABLE Topics (
topic_id SERIAL PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
created_by INT REFERENCES Users(user_id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create the Posts table
CREATE TABLE Posts (
post_id SERIAL PRIMARY KEY,
topic_id INT NOT NULL REFERENCES Topics(topic_id),
user_id INT NOT NULL REFERENCES Users(user_id),
title VARCHAR(255) NOT NULL,
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_reported BOOLEAN DEFAULT FALSE,
last_edited_at TIMESTAMP NULL
);
-- Insert sample data
INSERT INTO Users (username, email, join_date) VALUES
('forumFan', 'fan@example.com', '2023-01-15'),
('topicMaster', 'master@example.com', '2023-02-20'),
('postGuru', 'guru@example.com', '2023-03-10');
INSERT INTO Topics (name, description, created_by, created_at) VALUES
('Database Performance', 'Discussions about optimizing database queries.', 1, '2023-05-01 10:00:00'),
('Web Development Trends', 'Latest news and trends in web development.', 2, '2023-06-15 14:30:00'),
('General Chat', 'Off-topic discussions.', 1, '2023-01-20 09:00:00');
INSERT INTO Posts (topic_id, user_id, title, content, created_at, is_reported) VALUES
(1, 1, 'Indexing Strategies in PostgreSQL', 'Let us discuss B-Trees, Hash indexes...', '2023-05-02 11:00:00', FALSE),
(1, 2, 'Re: Indexing Strategies', 'Partial indexes are great for specific subsets!', '2023-05-03 09:20:00', FALSE),
(2, 3, 'Rise of Serverless', 'Is serverless the future?', '2023-06-16 10:00:00', FALSE),
(2, 1, 'Re: Rise of Serverless', 'Depends on the use case...', '2023-06-17 15:00:00', TRUE), -- Reported post
(3, 2, 'Favorite weekend hobbies?', 'What do you do on weekends?', '2023-01-21 11:00:00', FALSE),
(1, 3, 'Full-Text Search Tips', 'Using tsvector and tsquery...', '2023-07-01 14:00:00', FALSE);
Tasks:
- Basic Index: Create an index on the
Users
table to speed up lookups based onjoin_date
. - Foreign Key Index: Create an index on the
Posts
table to efficiently find all posts made by a specificuser_id
. - Foreign Key Index: Create an index on the
Posts
table to efficiently retrieve all posts belonging to a specifictopic_id
. - Multicolumn Index: Create a multicolumn index on the
Posts
table to optimize viewing posts within atopic_id
, ordered by theircreated_at
timestamp. Ensuretopic_id
is the leading column. - Partial Index: Create a partial index on the
Posts
table for thecreated_at
column, but only including entries whereis_reported
is TRUE. This is for the moderator’s review queue. - Index on Expression: Create an index on the
Posts
table using theLOWER()
function on thetitle
column to support fast, case-insensitive searches by post title. - Unique Index Explanation: The
Topics
table has aUNIQUE
constraint on thename
column. What does this constraint imply about indexing on that column? Is a separateCREATE INDEX
needed for basic lookups onname
? - List Indexes: Use the
\d Posts
meta-command (in psql or pgAdmin’s Query Tool SQL pane) to display all indexes associated with thePosts
table. - Reindex Table: Rebuild all indexes on the
Posts
table, assuming frequent edits and deletions might have occurred. - Drop Index: Remove the expression index created in step 6 (
LOWER(title)
onPosts
).
Variant 5: Flight Booking System
Scenario: You are developing the database backend for a flight booking system. Performance is critical for searching available flights between destinations, checking specific flight details, and managing passenger bookings. Indexes are needed to ensure quick query responses.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Bookings;
DROP TABLE IF EXISTS Flights;
DROP TABLE IF EXISTS Airlines;
DROP TABLE IF EXISTS Airports;
-- Create the Airports table
CREATE TABLE Airports (
airport_code CHAR(3) PRIMARY KEY, -- e.g., 'JFK', 'LAX'
name VARCHAR(100) NOT NULL,
city VARCHAR(100),
country VARCHAR(100)
);
-- Create the Airlines table
CREATE TABLE Airlines (
airline_id SERIAL PRIMARY KEY,
iata_code VARCHAR(3) UNIQUE NOT NULL, -- e.g., 'AA', 'UA'
name VARCHAR(100) NOT NULL
);
-- Create the Flights table
CREATE TABLE Flights (
flight_id SERIAL PRIMARY KEY,
flight_number VARCHAR(10) NOT NULL,
airline_id INT NOT NULL REFERENCES Airlines(airline_id),
departure_airport CHAR(3) NOT NULL REFERENCES Airports(airport_code),
arrival_airport CHAR(3) NOT NULL REFERENCES Airports(airport_code),
departure_time TIMESTAMP WITH TIME ZONE NOT NULL,
arrival_time TIMESTAMP WITH TIME ZONE NOT NULL,
base_price NUMERIC(10, 2) CHECK (base_price >= 0),
total_seats INT,
seats_booked INT DEFAULT 0
);
-- Create the Bookings table
CREATE TABLE Bookings (
booking_id SERIAL PRIMARY KEY,
flight_id INT NOT NULL REFERENCES Flights(flight_id),
passenger_name VARCHAR(150) NOT NULL,
seat_number VARCHAR(4), -- e.g., '12A', '30F'
booking_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'confirmed' -- 'confirmed', 'cancelled'
);
-- Insert sample data
INSERT INTO Airports (airport_code, name, city, country) VALUES
('JFK', 'John F. Kennedy International', 'New York', 'USA'),
('LAX', 'Los Angeles International', 'Los Angeles', 'USA'),
('LHR', 'London Heathrow', 'London', 'UK'),
('CDG', 'Charles de Gaulle', 'Paris', 'France');
INSERT INTO Airlines (iata_code, name) VALUES
('AA', 'American Airlines'),
('BA', 'British Airways'),
('DL', 'Delta Air Lines');
INSERT INTO Flights (flight_number, airline_id, departure_airport, arrival_airport, departure_time, arrival_time, base_price, total_seats) VALUES
('AA101', 1, 'JFK', 'LAX', '2024-07-15 09:00:00-04', '2024-07-15 12:00:00-07', 350.00, 180),
('BA286', 2, 'LHR', 'LAX', '2024-07-15 11:30:00+01', '2024-07-15 14:45:00-07', 680.00, 220),
('DL405', 3, 'JFK', 'CDG', '2024-07-16 18:00:00-04', '2024-07-17 07:30:00+02', 550.00, 200),
('AA202', 1, 'LAX', 'JFK', '2024-07-18 14:00:00-07', '2024-07-18 22:30:00-04', 360.00, 180);
INSERT INTO Bookings (flight_id, passenger_name, seat_number, status) VALUES
(1, 'Alice Wonderland', '15A', 'confirmed'),
(1, 'Bob The Builder', '15B', 'confirmed'),
(2, 'Charlie Chaplin', '22F', 'confirmed'),
(3, 'Diana Prince', '10C', 'cancelled'),
(4, 'Edward Scissorhands', '5A', 'confirmed');
-- Update seats_booked based on insertions
UPDATE Flights SET seats_booked = 2 WHERE flight_id = 1;
UPDATE Flights SET seats_booked = 1 WHERE flight_id = 2;
UPDATE Flights SET seats_booked = 0 WHERE flight_id = 3; -- Cancelled booking doesn't count
UPDATE Flights SET seats_booked = 1 WHERE flight_id = 4;
Tasks:
- Basic Index: Create an index on the
Airports
table to quickly search for airports located in a specificcity
. - Basic Index: Create an index on the
Flights
table to quickly find flights using theirflight_number
. - Multicolumn Index (Core Search): Create a crucial multicolumn index on the
Flights
table to optimize the most common search: finding flights based ondeparture_airport
,arrival_airport
, anddeparture_time
. Ensure columns are in this order. - Foreign Key Index: Create an index on the
Flights
table to efficiently find all flights operated by a specificairline_id
. - Foreign Key Index: Create an index on the
Bookings
table to quickly retrieve all bookings associated with a specificflight_id
. - Partial Index (Availability): Create a partial index on the
Flights
table coveringdeparture_time
, but only for flights whereseats_booked < total_seats
. This optimizes searches for flights that still have available seats. - Index on Expression (Date Search): Create an index on the
Flights
table based on the date part of thedeparture_time
column (useCAST(departure_time AS DATE)
orDATE(departure_time)
). This will speed up queries searching for all flights departing on a specific date, regardless of time. - Unique Index (Seat Assignment): Create a unique index on the
Bookings
table coveringflight_id
andseat_number
to prevent assigning the same seat on the same flight to multiple passengers. Allow NULLs inseat_number
if seat assignment can be optional initially (though the current schema implies it’s usually present). - List Indexes: Use the
pg_indexes
system catalog view to list all indexes currently defined for theFlights
table, showing their names and definitions. - Drop Index: Remove the basic index created in step 2 on the
flight_number
column of theFlights
table.
Variant 6: University Course Enrollment System
Scenario: You are managing the database for a university’s course enrollment system. Students, faculty, and administrators need fast access to course information, student schedules, class rosters, and departmental listings. Effective indexing is vital for the system’s responsiveness, especially during peak registration periods.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Enrollments;
DROP TABLE IF EXISTS Courses;
DROP TABLE IF EXISTS Departments;
DROP TABLE IF EXISTS Students;
-- Create the Students table
CREATE TABLE Students (
student_id SERIAL PRIMARY KEY,
student_uid VARCHAR(10) UNIQUE NOT NULL, -- University ID, e.g., 'u1234567'
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
enrollment_year INT,
major VARCHAR(100)
);
-- Create the Departments table
CREATE TABLE Departments (
dept_id SERIAL PRIMARY KEY,
dept_code VARCHAR(10) UNIQUE NOT NULL, -- e.g., 'CSCI', 'MATH'
name VARCHAR(150) NOT NULL
);
-- Create the Courses table
CREATE TABLE Courses (
course_id SERIAL PRIMARY KEY,
course_code VARCHAR(10) NOT NULL, -- e.g., '101', '315W'
title VARCHAR(200) NOT NULL,
credits INT CHECK (credits > 0),
dept_id INT NOT NULL REFERENCES Departments(dept_id),
UNIQUE (dept_id, course_code) -- Course code unique within a department
);
-- Create the Enrollments table
CREATE TABLE Enrollments (
enrollment_id SERIAL PRIMARY KEY,
student_id INT NOT NULL REFERENCES Students(student_id),
course_id INT NOT NULL REFERENCES Courses(course_id),
semester VARCHAR(20) NOT NULL, -- e.g., 'Fall 2024', 'Spring 2025'
registration_date DATE DEFAULT CURRENT_DATE,
grade CHAR(2) NULL, -- e.g., 'A', 'B+', 'P', 'F', NULL if in progress
UNIQUE (student_id, course_id, semester) -- Student cannot enroll in the same course multiple times in one semester
);
-- Insert sample data
INSERT INTO Students (student_uid, first_name, last_name, enrollment_year, major) VALUES
('u7654321', 'Hermione', 'Granger', 2021, 'Magical Law'),
('u1122334', 'Ron', 'Weasley', 2021, 'Defense Against Dark Arts'),
('u9876543', 'Harry', 'Potter', 2021, 'Auror Training');
INSERT INTO Departments (dept_code, name) VALUES
('CSCI', 'Computer Science'),
('MATH', 'Mathematics'),
('PHYS', 'Physics');
INSERT INTO Courses (course_code, title, credits, dept_id) VALUES
('101', 'Intro to Programming', 4, 1),
('210', 'Data Structures', 4, 1),
('151', 'Calculus I', 4, 2),
('201', 'Classical Mechanics', 3, 3);
INSERT INTO Enrollments (student_id, course_id, semester, grade) VALUES
(1, 1, 'Fall 2023', 'A'),
(1, 3, 'Fall 2023', 'A-'),
(2, 1, 'Fall 2023', 'C+'),
(3, 1, 'Spring 2024', NULL), -- In progress
(1, 2, 'Spring 2024', NULL), -- In progress
(2, 3, 'Spring 2024', NULL); -- In progress
Tasks:
- Basic Index: Create an index on the
Students
table to allow for efficient searching bylast_name
. - Foreign Key Index: Create an index on the
Courses
table to quickly find all courses offered by a specificdept_id
. - Foreign Key Index (Enrollments): Create an index on the
Enrollments
table to efficiently retrieve all courses a particularstudent_id
is enrolled in or has taken. - Foreign Key Index (Enrollments): Create an index on the
Enrollments
table to quickly generate a class roster (list of students) for a specificcourse_id
. - Multicolumn Index (Student Schedule): Create a multicolumn index on the
Enrollments
table to optimize fetching a specific student’s schedule for a givensemester
. The index should coverstudent_id
andsemester
, in that order. - Multicolumn Index (Course Roster): Create a multicolumn index on the
Enrollments
table to optimize fetching the roster for a specificcourse_id
within a particularsemester
. The index should covercourse_id
andsemester
, in that order. - Partial Index (In Progress): Create a partial index on the
Enrollments
table covering thecourse_id
column, but only for rows where thegrade
is NULL. This helps quickly find students currently enrolled in a course (ungraded). - Index on Expression (Case-Insensitive Major): Create an index on the
Students
table based on theLOWER()
function applied to themajor
column to support case-insensitive searches for students by major. - List Indexes: Use the
\d Enrollments
meta-command to list all indexes currently associated with theEnrollments
table. Verify the indexes created in previous steps are present. - Reindex and Drop: Rebuild all indexes on the
Students
table. Afterwards, drop the index created in step 1 (last_name
onStudents
).
Variant 7: Healthcare Appointment System
Scenario: You are responsible for managing the database of a clinic’s appointment scheduling system. Fast retrieval of patient information, available slots, and appointment history is critical for the clinic’s operations. You need to add indexes to optimize common lookup and filtering operations.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Appointments;
DROP TABLE IF EXISTS Patients;
DROP TABLE IF EXISTS Doctors;
-- Create the Doctors table
CREATE TABLE Doctors (
doctor_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
specialty VARCHAR(100),
license_number VARCHAR(50) UNIQUE NOT NULL
);
-- Create the Patients table
CREATE TABLE Patients (
patient_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE,
contact_phone VARCHAR(20) UNIQUE, -- Can be NULL but must be unique if present
registration_date DATE DEFAULT CURRENT_DATE
);
-- Create the Appointments table
CREATE TABLE Appointments (
appointment_id SERIAL PRIMARY KEY,
patient_id INT NOT NULL REFERENCES Patients(patient_id),
doctor_id INT NOT NULL REFERENCES Doctors(doctor_id),
appointment_datetime TIMESTAMP NOT NULL, -- Date and time of the appointment
duration_minutes INT DEFAULT 30 CHECK (duration_minutes > 0),
status VARCHAR(20) DEFAULT 'scheduled', -- e.g., 'scheduled', 'completed', 'cancelled', 'no_show'
reason TEXT -- Reason for the visit
);
-- Insert sample data
INSERT INTO Doctors (first_name, last_name, specialty, license_number) VALUES
('Alice', 'Chen', 'Cardiology', 'LIC1001'),
('Bob', 'Miller', 'Pediatrics', 'LIC1002'),
('Carol', 'Davis', 'General Practice', 'LIC1003');
INSERT INTO Patients (first_name, last_name, date_of_birth, contact_phone, registration_date) VALUES
('Mark', 'Johnson', '1985-06-15', '555-1234', '2023-01-10'),
('Sarah', 'Williams', '1992-09-22', '555-5678', '2023-02-20'),
('David', 'Brown', '1978-03-01', NULL, '2023-05-15'),
('Emily', 'Smith', '2018-11-12', '555-9900', '2023-06-01');
INSERT INTO Appointments (patient_id, doctor_id, appointment_datetime, duration_minutes, status, reason) VALUES
(1, 1, '2024-05-10 10:00:00', 45, 'completed', 'Annual Checkup'),
(2, 3, '2024-05-10 11:00:00', 30, 'scheduled', 'Consultation'),
(1, 1, '2024-05-17 14:00:00', 45, 'scheduled', 'Follow-up'),
(4, 2, '2024-05-18 09:30:00', 30, 'scheduled', 'Vaccination'),
(2, 3, '2024-04-25 15:00:00', 30, 'cancelled', 'Feeling better'),
(3, 3, '2024-05-20 16:00:00', 30, 'scheduled', 'New Patient Visit');
Tasks:
- Basic Index: Create an index on the
Patients
table to speed up searches based on the patient’slast_name
. - Unique Index: Create a unique index on the
Patients
table for thecontact_phone
column to enforce uniqueness for non-NULL phone numbers. - Foreign Key Index: Create an index on the
Appointments
table to efficiently retrieve all appointments for a specificpatient_id
. - Foreign Key Index: Create an index on the
Appointments
table to efficiently find all appointments scheduled with a specificdoctor_id
. - Multicolumn Index: Create a multicolumn index on the
Appointments
table to optimize queries that filter bydoctor_id
and then byappointment_datetime
. - Index on Expression: Create an index on the
Patients
table based on theYEAR
extracted from thedate_of_birth
to optimize queries searching for patients born in a specific year.CREATE INDEX idx_patients_birth_year ON Patients (EXTRACT(YEAR FROM date_of_birth));
- Partial Index: Create a partial index on the
Appointments
table for theappointment_datetime
column, but only include appointments with astatus
of ‘scheduled’. This helps optimize queries looking for upcoming, active appointments. - Reindex Table: Rebuild all indexes currently existing on the
Appointments
table. - List Indexes: Use the
\d Appointments
meta-command (in psql or pgAdmin’s Query Tool SQL pane) to view the indexes on theAppointments
table. - Drop Index: Remove the index created in step 6 (
idx_patients_birth_year
).
Variant 8: Warehouse Inventory System
Scenario: You manage the database for a warehouse inventory system. The system needs to track products, their locations within different warehouses, and current stock levels. Efficient querying for product availability, stock levels, and warehouse contents is crucial.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS InventoryLevels;
DROP TABLE IF EXISTS Products;
DROP TABLE IF EXISTS Warehouses;
-- Create the Warehouses table
CREATE TABLE Warehouses (
warehouse_id SERIAL PRIMARY KEY,
code VARCHAR(10) UNIQUE NOT NULL, -- e.g., 'NYC-01', 'LAX-02'
city VARCHAR(100) NOT NULL,
capacity_sqft INT,
is_refrigerated BOOLEAN DEFAULT FALSE
);
-- Create the Products table
CREATE TABLE Products (
product_id SERIAL PRIMARY KEY,
sku VARCHAR(50) UNIQUE NOT NULL, -- Stock Keeping Unit
name VARCHAR(200) NOT NULL,
category VARCHAR(100),
unit_cost NUMERIC(10, 2),
supplier_info JSONB -- Store supplier name, contact, etc.
);
-- Create the InventoryLevels table (linking Products and Warehouses)
CREATE TABLE InventoryLevels (
inventory_id SERIAL PRIMARY KEY,
product_id INT NOT NULL REFERENCES Products(product_id),
warehouse_id INT NOT NULL REFERENCES Warehouses(warehouse_id),
quantity INT NOT NULL CHECK (quantity >= 0),
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reorder_level INT DEFAULT 10,
UNIQUE (product_id, warehouse_id) -- A product exists only once per warehouse
);
-- Insert sample data
INSERT INTO Warehouses (code, city, capacity_sqft, is_refrigerated) VALUES
('NYC-01', 'New York', 50000, false),
('LAX-02', 'Los Angeles', 75000, true),
('CHI-01', 'Chicago', 60000, false);
INSERT INTO Products (sku, name, category, unit_cost, supplier_info) VALUES
('ELE-TV-55', '55-inch 4K TV', 'Electronics', 350.00, '{"name": "PanelCorp", "contact": "sales@panelcorp.com"}'),
('FUR-DSK-WD', 'Wooden Desk', 'Furniture', 120.50, '{"name": "WoodWorks Ltd.", "contact": "orders@woodworksltd.net"}'),
('GRC-APL-FU', 'Fuji Apples (Box)', 'Grocery', 15.75, '{"name": "FreshFarms Inc.", "region": "WA"}'),
('ELE-CAM-DL', 'Digital SLR Camera', 'Electronics', 899.00, '{"name": "LensMasters", "contact": "info@lensmasters.com"}');
INSERT INTO InventoryLevels (product_id, warehouse_id, quantity, reorder_level) VALUES
(1, 1, 50, 10), -- TV in NYC
(1, 3, 75, 15), -- TV in Chicago
(2, 1, 120, 20), -- Desk in NYC
(3, 2, 200, 50), -- Apples in LA (requires refrigeration)
(4, 1, 25, 5), -- Camera in NYC
(4, 3, 30, 5); -- Camera in Chicago
Tasks:
- Basic Index: Create an index on the
Products
table to speed up searches based on the productname
. - Basic Index: Create an index on the
Warehouses
table to enable faster lookups bycity
. - Foreign Key Index: Create an index on the
InventoryLevels
table to efficiently query stock levels for a specificproduct_id
across all warehouses. - Foreign Key Index: Create an index on the
InventoryLevels
table to quickly find all products stored within a specificwarehouse_id
. - Multicolumn Index: The
InventoryLevels
table already has a unique constraint (and thus an underlying index) on(product_id, warehouse_id)
. Explain why creating another indexON InventoryLevels (warehouse_id, product_id)
might still be beneficial for certain queries. - Partial Index: Create a partial index on the
InventoryLevels
table for thequantity
column, but only include rows wherequantity
is less than thereorder_level
. This helps efficiently identify items needing restocking.CREATE INDEX idx_inventory_low_stock ON InventoryLevels (product_id, warehouse_id) WHERE quantity < reorder_level;
- Index on Expression: Create an index on the
Products
table based on the lowercase version of thecategory
column to facilitate case-insensitive category searches. - GIN Index (JSONB): Create a GIN index on the
supplier_info
column in theProducts
table to efficiently query based on keys or values within the JSONB data (e.g., finding products from a specific supplier name).CREATE INDEX idx_products_supplier_info_gin ON Products USING gin (supplier_info);
- List Indexes: Use the
pg_indexes
system catalog view to list all indexes associated with theInventoryLevels
table. - Drop Index: Remove the expression index created in step 7 (
LOWER(category)
onProducts
).
Variant 9: Blog Platform
Scenario: You are the database administrator for a blogging platform. Users need to be able to quickly find posts by author, tag, or date, and view comments associated with posts. You must add indexes to support these features efficiently.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS PostTags;
DROP TABLE IF EXISTS Comments;
DROP TABLE IF EXISTS Tags;
DROP TABLE IF EXISTS Posts;
DROP TABLE IF EXISTS Users;
-- Create the Users table
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
join_date DATE DEFAULT CURRENT_DATE
);
-- Create the Posts table
CREATE TABLE Posts (
post_id SERIAL PRIMARY KEY,
author_id INT NOT NULL REFERENCES Users(user_id),
title VARCHAR(255) NOT NULL,
content TEXT,
published_at TIMESTAMP, -- NULL if draft
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(15) DEFAULT 'draft' -- e.g., 'draft', 'published', 'archived'
);
-- Create the Comments table
CREATE TABLE Comments (
comment_id SERIAL PRIMARY KEY,
post_id INT NOT NULL REFERENCES Posts(post_id) ON DELETE CASCADE,
user_id INT NOT NULL REFERENCES Users(user_id), -- Comment author
comment_text TEXT NOT NULL,
commented_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create the Tags table
CREATE TABLE Tags (
tag_id SERIAL PRIMARY KEY,
tag_name VARCHAR(50) UNIQUE NOT NULL
);
-- Create the PostTags table (Many-to-Many link)
CREATE TABLE PostTags (
post_id INT NOT NULL REFERENCES Posts(post_id) ON DELETE CASCADE,
tag_id INT NOT NULL REFERENCES Tags(tag_id) ON DELETE CASCADE,
PRIMARY KEY (post_id, tag_id) -- Ensures a tag is applied only once per post
);
-- Insert sample data
INSERT INTO Users (username, email) VALUES
('blogger_a', 'a@example.com'),
('reader_b', 'b@example.com'),
('editor_c', 'c@example.com');
INSERT INTO Posts (author_id, title, content, published_at, status) VALUES
(1, 'My First Post', 'This is the content of my first post.', '2024-01-15 10:00:00', 'published'),
(1, 'Advanced SQL Tricks', 'Let us talk about window functions...', '2024-02-20 11:30:00', 'published'),
(3, 'Editing Guidelines', 'Please follow these guidelines...', '2024-03-01 09:00:00', 'published'),
(1, 'Draft Post Idea', 'Something about databases...', NULL, 'draft');
INSERT INTO Comments (post_id, user_id, comment_text) VALUES
(1, 2, 'Great first post!'),
(2, 2, 'Very useful SQL tips, thanks!'),
(2, 3, 'Well written, approved.'),
(1, 1, 'Thanks for the feedback!'); -- Author replying
INSERT INTO Tags (tag_name) VALUES
('introduction'), ('sql'), ('databases'), ('guide'), ('meta');
INSERT INTO PostTags (post_id, tag_id) VALUES
(1, 1), -- Post 1 tagged 'introduction'
(2, 2), -- Post 2 tagged 'sql'
(2, 3), -- Post 2 tagged 'databases'
(3, 4), -- Post 3 tagged 'guide'
(3, 5); -- Post 3 tagged 'meta'
Tasks:
- Basic Index: Create an index on the
Posts
table to quickly find all posts written by a specificauthor_id
. - Basic Index: Create an index on the
Comments
table to quickly retrieve all comments left by a specificuser_id
. - Foreign Key Index: Create an index on the
Comments
table to efficiently fetch all comments belonging to a specificpost_id
. - Foreign Key Index (M2M): Create an index on the
PostTags
table to efficiently find all tags associated with a givenpost_id
. (Note: The primary key already covers(post_id, tag_id)
, but an index specifically onpost_id
might be used differently by the planner). - Foreign Key Index (M2M): Create an index on the
PostTags
table to efficiently find all posts associated with a giventag_id
. - Multicolumn Index: Create a multicolumn index on the
Posts
table to optimize queries searching for posts by a specificauthor_id
that also filter bystatus
(e.g., find all ‘published’ posts by author X). - Index on Expression: Create an index on the
Posts
table using theDATE()
function on thepublished_at
column to optimize queries filtering posts published on a specific date (ignoring the time component).CREATE INDEX idx_posts_publish_date ON Posts (DATE(published_at));
- Partial Index: Create a partial index on the
Posts
table for thepublished_at
column, but only include rows where thestatus
is ‘published’. This is useful for efficiently querying or sorting only the published posts by date. - List Indexes: Use the
\d PostTags
meta-command to view the indexes (including the primary key index) on thePostTags
table. - Drop Index: Remove the index created in step 7 (
idx_posts_publish_date
).
Variant 10: Restaurant Reservation System
Scenario: You are managing the database for an online restaurant reservation platform. Efficiently finding restaurants, checking table availability, and managing customer reservations are key functionalities. You need to add indexes to optimize query performance.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Reservations;
DROP TABLE IF EXISTS RestaurantTables;
DROP TABLE IF EXISTS Customers;
DROP TABLE IF EXISTS Restaurants;
-- Create the Restaurants table
CREATE TABLE Restaurants (
restaurant_id SERIAL PRIMARY KEY,
name VARCHAR(150) NOT NULL,
cuisine_type VARCHAR(50),
city VARCHAR(100),
rating NUMERIC(3, 2) CHECK (rating >= 0 AND rating <= 5), -- e.g., 4.50
phone_number VARCHAR(20) UNIQUE
);
-- Create the RestaurantTables table
CREATE TABLE RestaurantTables (
table_id SERIAL PRIMARY KEY,
restaurant_id INT NOT NULL REFERENCES Restaurants(restaurant_id),
table_number VARCHAR(10), -- e.g., 'T1', 'P2' (Patio 2)
capacity INT NOT NULL CHECK (capacity > 0),
is_available BOOLEAN DEFAULT TRUE
);
-- Create the Customers table
CREATE TABLE Customers (
customer_id SERIAL PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
phone VARCHAR(20)
);
-- Create the Reservations table
CREATE TABLE Reservations (
reservation_id SERIAL PRIMARY KEY,
customer_id INT NOT NULL REFERENCES Customers(customer_id),
table_id INT NOT NULL REFERENCES RestaurantTables(table_id),
reservation_time TIMESTAMP NOT NULL,
party_size INT NOT NULL CHECK (party_size > 0),
status VARCHAR(20) DEFAULT 'confirmed', -- 'confirmed', 'cancelled', 'completed', 'no-show'
special_requests TEXT
);
-- Insert sample data
INSERT INTO Restaurants (name, cuisine_type, city, rating, phone_number) VALUES
('The Gourmet Place', 'French', 'Metropolis', 4.80, '555-0101'),
('Pasta Paradise', 'Italian', 'Metropolis', 4.50, '555-0102'),
('Sushi Central', 'Japanese', 'Gotham', 4.70, '555-0201'),
('Taco Town', 'Mexican', 'Metropolis', 4.20, '555-0103');
INSERT INTO RestaurantTables (restaurant_id, table_number, capacity, is_available) VALUES
(1, 'T1', 2, TRUE), (1, 'T2', 4, TRUE), (1, 'T3', 4, FALSE),
(2, 'P1', 4, TRUE), (2, 'P2', 6, TRUE),
(3, 'S1', 2, TRUE), (3, 'S2', 2, TRUE), (3, 'B1', 8, TRUE), -- Sushi Bar
(4, 'M1', 4, TRUE);
INSERT INTO Customers (first_name, last_name, email, phone) VALUES
('Clark', 'Kent', 'clark.k@dailyplanet.com', '555-1111'),
('Lois', 'Lane', 'lois.l@dailyplanet.com', '555-2222'),
('Bruce', 'Wayne', 'bruce@waynecorp.com', '555-3333');
INSERT INTO Reservations (customer_id, table_id, reservation_time, party_size, status) VALUES
(1, 2, '2024-06-15 19:00:00', 2, 'confirmed'), -- Clark at Gourmet Place T2
(2, 4, '2024-06-16 20:00:00', 4, 'confirmed'), -- Lois at Pasta Paradise P1
(3, 8, '2024-06-17 18:30:00', 6, 'confirmed'), -- Bruce at Sushi Central B1
(1, 5, '2024-06-18 19:30:00', 5, 'cancelled'); -- Clark at Pasta Paradise P2 (cancelled)
Tasks:
- Basic Index: Create an index on the
Restaurants
table to speed up searches based on the restaurantname
. - Basic Index: Create an index on the
Customers
table to quickly find customers by theirlast_name
. - Foreign Key Index: Create an index on the
RestaurantTables
table to efficiently find all tables belonging to a specificrestaurant_id
. - Foreign Key Index: Create an index on the
Reservations
table to quickly look up reservations made by a specificcustomer_id
. - Foreign Key Index: Create an index on the
Reservations
table to quickly find all reservations associated with a specifictable_id
. - Multicolumn Index: Create a multicolumn index on the
Restaurants
table to optimize searches filtering bycity
first and then bycuisine_type
. - Multicolumn Index: Create a multicolumn index on the
Reservations
table to efficiently query reservations based onreservation_time
andstatus
. Placereservation_time
first in the index definition. - Partial Index: Create a partial index on the
Reservations
table for thereservation_time
column, but only include reservations with a status of ‘confirmed’. This helps efficiently find active, upcoming reservations. - Index on Expression: Create an index on the
Customers
table using theLOWER()
function on theemail
column to support case-insensitive email lookups (even though there’s a unique constraint, this supports queries usingLOWER()
). - List and Drop: Use the
\d Reservations
meta-command to list indexes on theReservations
table. Then, drop the index created in step 8 (the partial index onreservation_time
for ‘confirmed’ status).
Variant 11: Event Ticketing System
Scenario: You are developing the database for an online event ticketing platform. Users need to quickly search for events, view ticket availability and pricing, and manage their purchases. Indexing is crucial for handling high traffic during popular event sales.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Purchases;
DROP TABLE IF EXISTS TicketTypes;
DROP TABLE IF EXISTS Events;
DROP TABLE IF EXISTS Venues;
DROP TABLE IF EXISTS Users; -- Assuming a generic Users table
-- Create the Venues table
CREATE TABLE Venues (
venue_id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
city VARCHAR(100),
capacity INT
);
-- Create the Events table
CREATE TABLE Events (
event_id SERIAL PRIMARY KEY,
venue_id INT REFERENCES Venues(venue_id),
name VARCHAR(255) NOT NULL,
category VARCHAR(50), -- e.g., 'Music', 'Sports', 'Theater', 'Conference'
event_start_time TIMESTAMP NOT NULL,
event_end_time TIMESTAMP,
status VARCHAR(20) DEFAULT 'scheduled' -- 'scheduled', 'cancelled', 'postponed', 'completed'
);
-- Create the TicketTypes table (defines price levels/sections for an event)
CREATE TABLE TicketTypes (
ticket_type_id SERIAL PRIMARY KEY,
event_id INT NOT NULL REFERENCES Events(event_id),
description VARCHAR(100), -- e.g., 'General Admission', 'VIP', 'Balcony Section A'
price NUMERIC(10, 2) NOT NULL CHECK (price >= 0),
total_quantity INT NOT NULL CHECK (total_quantity >= 0), -- Total tickets of this type available
available_quantity INT CHECK (available_quantity >= 0 AND available_quantity <= total_quantity)
);
-- Create the Users table (simplified)
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
email VARCHAR(150) UNIQUE NOT NULL,
name VARCHAR(150)
);
-- Create the Purchases table
CREATE TABLE Purchases (
purchase_id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES Users(user_id),
ticket_type_id INT NOT NULL REFERENCES TicketTypes(ticket_type_id),
quantity INT NOT NULL CHECK (quantity > 0),
purchase_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
total_cost NUMERIC(12, 2),
confirmation_code VARCHAR(32) UNIQUE NOT NULL -- Unique code for this purchase transaction
);
-- Insert sample data
INSERT INTO Venues (name, city, capacity) VALUES
('Arena Central', 'Metropolis', 15000),
('Grand Theater', 'Gotham', 2500),
('Open Air Park', 'Metropolis', 30000);
INSERT INTO Events (venue_id, name, category, event_start_time, status) VALUES
(1, 'Rock Legends Concert', 'Music', '2024-08-15 20:00:00', 'scheduled'),
(2, 'Shakespeare''s Hamlet', 'Theater', '2024-09-10 19:30:00', 'scheduled'),
(1, 'Tech Conference 2024', 'Conference', '2024-10-01 09:00:00', 'scheduled'),
(3, 'Summer Music Festival', 'Music', '2024-07-20 12:00:00', 'completed');
INSERT INTO TicketTypes (event_id, description, price, total_quantity, available_quantity) VALUES
(1, 'Floor Standing', 75.00, 5000, 3500), (1, 'Lower Bowl Seat', 120.00, 8000, 6000), (1, 'VIP Box', 300.00, 100, 20),
(2, 'Orchestra', 90.00, 500, 450), (2, 'Mezzanine', 65.00, 1000, 800),
(3, 'Standard Pass', 499.00, 2000, 1500), (3, 'Workshop Addon', 150.00, 500, 300);
INSERT INTO Users (email, name) VALUES
('fan1@email.com', 'Alex Fan'),
('theater_lover@email.com', 'Bella Critic'),
('techguru@email.com', 'Charlie Dev');
INSERT INTO Purchases (user_id, ticket_type_id, quantity, total_cost, confirmation_code) VALUES
(1, 1, 2, 150.00, 'CONF-ROCK-12345ABC'), -- Alex buys 2 floor tickets for Rock Legends
(2, 4, 1, 90.00, 'CONF-HAMLET-67890DEF'), -- Bella buys 1 orchestra ticket for Hamlet
(1, 2, 4, 480.00, 'CONF-ROCK-11223XYZ'), -- Alex buys 4 lower bowl tickets for Rock Legends
(3, 6, 1, 499.00, 'CONF-TECH-44556UVW'); -- Charlie buys 1 standard pass for Tech Conference
Tasks:
- Basic Index: Create an index on the
Events
table to quickly search for events byname
. - Basic Index: Create an index on the
Venues
table to optimize searches bycity
. - Foreign Key Index: Create an index on the
Events
table to efficiently find all events happening at a specificvenue_id
. - Foreign Key Index: Create an index on the
TicketTypes
table to quickly retrieve all ticket types associated with a particularevent_id
. - Foreign Key Index: Create an index on the
Purchases
table to rapidly find all purchases made by a specificuser_id
. - Multicolumn Index: Create a multicolumn index on the
Events
table to optimize queries filtering first bycategory
and then byevent_start_time
. - Multicolumn Index: Create a multicolumn index on the
TicketTypes
table to support efficient queries filtering byevent_id
and sorting/filtering byprice
. - Partial Index: Create a partial index on the
Events
table for theevent_start_time
column, but only include events whose status is ‘scheduled’ or ‘postponed’. This helps in quickly finding upcoming or rescheduled events. - Reindex Table: Rebuild all indexes on the
Purchases
table. This might be done periodically if purchase data changes frequently (e.g., refunds causing deletes/updates). - List and Drop: Use the
pg_indexes
system view to list all indexes on theEvents
table. Then, drop the index created in step 8 (the partial index onevent_start_time
).
Variant 12: Job Board Platform
Scenario: You are responsible for the database behind a job board website. Fast searches for jobs based on location, category, and keywords are essential, as is efficiently retrieving applications for specific jobs or candidates. Indexing is vital for performance.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Applications;
DROP TABLE IF EXISTS Jobs;
DROP TABLE IF EXISTS Companies;
DROP TABLE IF EXISTS Candidates;
-- Create the Companies table
CREATE TABLE Companies (
company_id SERIAL PRIMARY KEY,
name VARCHAR(150) NOT NULL UNIQUE,
industry VARCHAR(100),
headquarters_location VARCHAR(150)
);
-- Create the Jobs table
CREATE TABLE Jobs (
job_id SERIAL PRIMARY KEY,
company_id INT NOT NULL REFERENCES Companies(company_id),
title VARCHAR(200) NOT NULL,
job_description TEXT,
category VARCHAR(100), -- e.g., 'Engineering', 'Marketing', 'Sales', 'Design'
location VARCHAR(150), -- Can be 'Remote' or a city/state
salary_range VARCHAR(50), -- e.g., '$80k-$100k', 'Competitive'
date_posted DATE DEFAULT CURRENT_DATE,
is_active BOOLEAN DEFAULT TRUE
);
-- Create the Candidates table
CREATE TABLE Candidates (
candidate_id SERIAL PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
phone VARCHAR(20),
primary_skill VARCHAR(100), -- e.g., 'Python', 'Project Management', 'Graphic Design'
resume_url VARCHAR(255) -- Link to stored resume file
);
-- Create the Applications table
CREATE TABLE Applications (
application_id SERIAL PRIMARY KEY,
job_id INT NOT NULL REFERENCES Jobs(job_id),
candidate_id INT NOT NULL REFERENCES Candidates(candidate_id),
application_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(30) DEFAULT 'submitted', -- 'submitted', 'viewed', 'interviewing', 'offered', 'rejected', 'withdrawn'
cover_letter TEXT,
UNIQUE (job_id, candidate_id) -- Prevent duplicate applications
);
-- Insert sample data
INSERT INTO Companies (name, industry, headquarters_location) VALUES
('Innovate Solutions', 'Technology', 'San Francisco, CA'),
('Global Marketing Inc.', 'Marketing', 'New York, NY'),
('BuildWell Construction', 'Construction', 'Austin, TX');
INSERT INTO Jobs (company_id, title, category, location, salary_range, is_active) VALUES
(1, 'Senior Software Engineer', 'Engineering', 'Remote', '$120k-$160k', TRUE),
(1, 'Backend Developer', 'Engineering', 'San Francisco, CA', '$100k-$130k', TRUE),
(2, 'Digital Marketing Manager', 'Marketing', 'New York, NY', '$90k-$110k', TRUE),
(3, 'Project Manager', 'Construction', 'Austin, TX', '$85k-$105k', TRUE),
(1, 'UI/UX Designer', 'Design', 'Remote', null, FALSE); -- Inactive job
INSERT INTO Candidates (first_name, last_name, email, primary_skill) VALUES
('Sarah', 'Chen', 'sarah.c@email.com', 'Python'),
('Michael', 'Bolton', 'm.bolton@email.com', 'JavaScript'),
('Priya', 'Sharma', 'priya.s@email.com', 'Digital Marketing'),
('David', 'Lee', 'david.lee@email.com', 'Project Management');
INSERT INTO Applications (job_id, candidate_id, status) VALUES
(1, 1, 'submitted'), -- Sarah applied for Senior Software Engineer
(2, 2, 'submitted'), -- Michael applied for Backend Developer
(3, 3, 'interviewing'), -- Priya applied for Digital Marketing Manager
(1, 2, 'viewed'), -- Michael also applied for Senior Software Engineer
(4, 4, 'submitted'); -- David applied for Project Manager
Tasks:
- Basic Index: Create an index on the
Jobs
table to speed up searches based on the jobtitle
. - Basic Index: Create an index on the
Companies
table to allow faster lookups by companyname
. - Foreign Key Index: Create an index on the
Jobs
table to efficiently find all jobs posted by a specificcompany_id
. - Foreign Key Index: Create an index on the
Applications
table to quickly retrieve all applications submitted for a specificjob_id
. - Foreign Key Index: Create an index on the
Applications
table to quickly find all jobs a specificcandidate_id
has applied for. - Multicolumn Index: Create a multicolumn index on the
Jobs
table to optimize queries filtering first bylocation
and then bycategory
. - Multicolumn Index: Create a multicolumn index on the
Applications
table to efficiently query applications based onjob_id
andapplication_date
. Placejob_id
first. - Partial Index: Create a partial index on the
Jobs
table covering thedate_posted
column, but only for jobs whereis_active
is TRUE. This helps efficiently find currently active job listings sorted by posting date. - Index on Expression: Create an index on the
Jobs
table using theLOWER()
function on thetitle
column to support case-insensitive title searches. - List and Drop: Use the
pg_indexes
system view to list all indexes associated with theApplications
table. Then, drop the multicolumn index created in step 7 (onjob_id
,application_date
).
Variant 13: Music Streaming Service
Scenario: You are managing the database for a music streaming service. Users need to be able to quickly search for artists, albums, and tracks, and manage their playlists efficiently. Indexes are required to ensure a smooth user experience.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS PlaylistTracks;
DROP TABLE IF EXISTS UserPlaylists;
DROP TABLE IF EXISTS Tracks;
DROP TABLE IF EXISTS Albums;
DROP TABLE IF EXISTS Artists;
-- Create the Artists table
CREATE TABLE Artists (
artist_id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
genre VARCHAR(100),
country VARCHAR(100)
);
-- Create the Albums table
CREATE TABLE Albums (
album_id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
artist_id INT NOT NULL REFERENCES Artists(artist_id),
release_year INT CHECK (release_year > 1800),
record_label VARCHAR(150)
);
-- Create the Tracks table
CREATE TABLE Tracks (
track_id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
album_id INT NOT NULL REFERENCES Albums(album_id),
duration_seconds INT CHECK (duration_seconds > 0),
track_number INT -- Position of the track within the album
);
-- Create the UserPlaylists table
CREATE TABLE UserPlaylists (
playlist_id SERIAL PRIMARY KEY,
user_id INT NOT NULL, -- Assuming a Users table exists elsewhere
name VARCHAR(150) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create the PlaylistTracks table (linking UserPlaylists and Tracks)
CREATE TABLE PlaylistTracks (
playlist_track_id SERIAL PRIMARY KEY,
playlist_id INT NOT NULL REFERENCES UserPlaylists(playlist_id) ON DELETE CASCADE,
track_id INT NOT NULL REFERENCES Tracks(track_id) ON DELETE CASCADE,
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (playlist_id, track_id) -- A track can only be in a specific playlist once
);
-- Insert sample data
INSERT INTO Artists (name, genre, country) VALUES
('Queen', 'Rock', 'UK'),
('Daft Punk', 'Electronic', 'France'),
('Miles Davis', 'Jazz', 'USA'),
('Taylor Swift', 'Pop', 'USA');
INSERT INTO Albums (title, artist_id, release_year, record_label) VALUES
('A Night at the Opera', 1, 1975, 'EMI'),
('Discovery', 2, 2001, 'Virgin'),
('Kind of Blue', 3, 1959, 'Columbia'),
('1989', 4, 2014, 'Big Machine');
INSERT INTO Tracks (title, album_id, duration_seconds, track_number) VALUES
('Bohemian Rhapsody', 1, 355, 11),
('Love of My Life', 1, 219, 9),
('One More Time', 2, 320, 1),
('Digital Love', 2, 301, 3),
('So What', 3, 562, 1),
('All Blues', 3, 693, 4),
('Shake It Off', 4, 219, 6),
('Blank Space', 4, 231, 2);
INSERT INTO UserPlaylists (user_id, name) VALUES
(101, 'Workout Mix'),
(102, 'Chill Vibes');
INSERT INTO PlaylistTracks (playlist_id, track_id) VALUES
(1, 1), (1, 3), (1, 7),
(2, 2), (2, 4), (2, 5), (2, 6);
Tasks:
- Basic Index: Create an index on the
Artists
table to optimize searching for artists byname
. - Basic Index: Create an index on the
Albums
table to speed up lookups based on the albumtitle
. - Foreign Key Index: Create an index on the
Albums
table’sartist_id
column to efficiently find all albums by a specific artist. - Foreign Key Index: Create an index on the
Tracks
table’salbum_id
column to quickly retrieve all tracks belonging to a particular album. - Multicolumn Index: Create a multicolumn index on the
Tracks
table using(album_id, track_number)
to optimize fetching tracks for an album in their correct order. - Foreign Key Index (Junction Table): Create an index on the
PlaylistTracks
table for theplaylist_id
column to rapidly find all tracks in a specific playlist. - Foreign Key Index (Junction Table): Create an index on the
PlaylistTracks
table for thetrack_id
column to quickly determine which playlists contain a specific track. - Partial Index: Create a partial index on the
Albums
table for therelease_year
column, indexing only albums released after the year 2000 (inclusive). This speeds up queries focused on modern music. - Index on Expression: Create an index on the
Tracks
table to support case-insensitive searches for track titles usingLOWER(title)
. - List and Drop: Use the
pg_indexes
system view to list all indexes associated with theTracks
table. Then, drop the case-insensitive title index created in the previous step.
Variant 14: Real Estate Listing Platform
Scenario: You are developing the database for a real estate website. Users need to search for properties based on location, price, size, and features. Agents list properties, and performance is key for search functionality.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS PropertyFeatures;
DROP TABLE IF EXISTS Listings;
DROP TABLE IF EXISTS Properties;
DROP TABLE IF EXISTS Agents;
-- Create the Agents table
CREATE TABLE Agents (
agent_id SERIAL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
agency VARCHAR(150),
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20)
);
-- Create the Properties table
CREATE TABLE Properties (
property_id SERIAL PRIMARY KEY,
address VARCHAR(255) NOT NULL,
city VARCHAR(100) NOT NULL,
state VARCHAR(50) NOT NULL,
zip_code VARCHAR(10) NOT NULL,
property_type VARCHAR(50), -- e.g., 'Single Family', 'Condo', 'Townhouse'
beds INT CHECK (beds >= 0),
baths NUMERIC(3,1) CHECK (baths >= 0), -- Allows for half baths (e.g., 2.5)
square_footage INT CHECK (square_footage > 0),
year_built INT
);
-- Create the Listings table
CREATE TABLE Listings (
listing_id SERIAL PRIMARY KEY,
property_id INT NOT NULL UNIQUE REFERENCES Properties(property_id), -- Ensures a property has only one active listing at a time
agent_id INT NOT NULL REFERENCES Agents(agent_id),
list_price NUMERIC(14, 2) NOT NULL CHECK (list_price > 0),
listing_date DATE NOT NULL DEFAULT CURRENT_DATE,
status VARCHAR(20) DEFAULT 'active' -- e.g., 'active', 'pending', 'sold', 'withdrawn'
);
-- Create the PropertyFeatures table (Many-to-Many for features)
CREATE TABLE PropertyFeatures (
feature_id SERIAL PRIMARY KEY,
property_id INT NOT NULL REFERENCES Properties(property_id) ON DELETE CASCADE,
feature_name VARCHAR(100) NOT NULL, -- e.g., 'Pool', 'Garage', 'Fireplace', 'Waterfront'
UNIQUE (property_id, feature_name)
);
-- Insert sample data
INSERT INTO Agents (first_name, last_name, agency, email, phone) VALUES
('Samantha', 'Green', 'Elite Homes', 'sam.g@elite.com', '555-1111'),
('David', 'Cho', 'Premier Properties', 'd.cho@premier.com', '555-2222'),
('Maria', 'Garcia', 'Elite Homes', 'maria.g@elite.com', '555-3333');
INSERT INTO Properties (address, city, state, zip_code, property_type, beds, baths, square_footage, year_built) VALUES
('123 Oak St', 'Maplewood', 'CA', '90210', 'Single Family', 4, 2.5, 2400, 1995),
('456 Pine Ave', 'Maplewood', 'CA', '90211', 'Condo', 2, 2, 1200, 2010),
('789 Elm Rd', 'Springfield', 'IL', '62704', 'Single Family', 3, 2, 1800, 1980),
('101 Maple Dr', 'Maplewood', 'CA', '90210', 'Townhouse', 3, 2.5, 1600, 2005);
INSERT INTO Listings (property_id, agent_id, list_price, listing_date, status) VALUES
(1, 1, 850000.00, '2024-02-15', 'active'),
(2, 2, 450000.00, '2024-03-01', 'active'),
(3, 1, 320000.00, '2024-01-20', 'pending'),
(4, 3, 510000.00, '2024-03-10', 'active');
INSERT INTO PropertyFeatures (property_id, feature_name) VALUES
(1, 'Pool'), (1, 'Garage'),
(2, 'Garage'), (2, 'Gym Access'),
(3, 'Fireplace'), (3, 'Large Yard'),
(4, 'Garage');
Tasks:
- Basic Index: Create a basic index on the
Properties
table to speed up searches based on thecity
. - Multicolumn Index: Create a multicolumn index on the
Properties
table for(state, city)
to optimize searches filtered first by state, then by city. - Foreign Key Index: Create an index on the
Listings
table for theagent_id
column to efficiently find all listings managed by a specific agent. - Index for Unique Constraint: An index is automatically created for the
UNIQUE
constraint onListings.property_id
. However, create an explicit index on this column as well (some DBAs prefer this for clarity or specific performance tuning, though redundant with the constraint’s index). Name itidx_listings_property_explicit
. - Multicolumn Index: Create a multicolumn index on the
Listings
table for(status, list_price)
to optimize finding listings by status (e.g., ‘active’) and then filtering or sorting by price. - Basic Index: Create an index on the
Properties
table for theproperty_type
column. - Partial Index: Create a partial index on the
Listings
table including only rows wherestatus = 'active'
. This index should cover thelist_price
column to optimize searches for active listings within a price range. - Index on Expression: Create an index on the
Properties
table usingUPPER(zip_code)
to facilitate case-insensitive zip code lookups (though zip codes are typically uniform, this demonstrates the concept). - Foreign Key Index (Many-to-Many): Create an index on the
PropertyFeatures
table for theproperty_id
column to quickly find all features associated with a property. - Reindex and List: Rebuild all indexes on the
Properties
table. Then, use the\d Listings
command (in psql or pgAdmin’s Query Tool SQL pane) to display the structure and indexes of theListings
table.
Variant 15: Bug Tracking System
Scenario: You are the administrator for a software bug tracking system. Developers and QA engineers need to efficiently search, filter, and update bugs based on project, status, priority, and assignee. Indexes are crucial for keeping the system responsive.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS BugComments;
DROP TABLE IF EXISTS Bugs;
DROP TABLE IF EXISTS Projects;
DROP TABLE IF EXISTS Users;
-- Create the Users table (simplified)
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
full_name VARCHAR(150),
email VARCHAR(100) UNIQUE NOT NULL
);
-- Create the Projects table
CREATE TABLE Projects (
project_id SERIAL PRIMARY KEY,
project_name VARCHAR(100) UNIQUE NOT NULL,
description TEXT
);
-- Create the Bugs table
CREATE TABLE Bugs (
bug_id SERIAL PRIMARY KEY,
project_id INT NOT NULL REFERENCES Projects(project_id),
title VARCHAR(255) NOT NULL,
description TEXT,
reported_by_user_id INT NOT NULL REFERENCES Users(user_id),
assigned_to_user_id INT REFERENCES Users(user_id), -- Can be NULL if unassigned
status VARCHAR(20) NOT NULL DEFAULT 'new', -- e.g., 'new', 'assigned', 'in_progress', 'resolved', 'closed', 'reopened'
priority VARCHAR(15) NOT NULL DEFAULT 'medium', -- e.g., 'low', 'medium', 'high', 'critical'
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create the BugComments table
CREATE TABLE BugComments (
comment_id SERIAL PRIMARY KEY,
bug_id INT NOT NULL REFERENCES Bugs(bug_id) ON DELETE CASCADE,
user_id INT NOT NULL REFERENCES Users(user_id),
comment_text TEXT NOT NULL,
commented_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert sample data
INSERT INTO Users (username, full_name, email) VALUES
('dev1', 'Alice Developer', 'alice.dev@company.com'),
('qa1', 'Bob Tester', 'bob.qa@company.com'),
('mgr1', 'Charlie Manager', 'charlie.mgr@company.com');
INSERT INTO Projects (project_name, description) VALUES
('WebApp V2', 'Main customer-facing web application'),
('MobileApp', 'iOS and Android companion app'),
('Backend API', 'Internal API services');
INSERT INTO Bugs (project_id, title, description, reported_by_user_id, assigned_to_user_id, status, priority, created_at, updated_at) VALUES
(1, 'Login button unresponsive on Firefox', 'Users on Firefox cannot click the login button.', 2, 1, 'assigned', 'high', '2024-03-01 10:00:00', '2024-03-01 11:30:00'),
(1, 'Incorrect currency symbol on checkout page', 'Shows USD instead of EUR for European users.', 2, 1, 'in_progress', 'medium', '2024-03-05 14:15:00', '2024-03-06 09:00:00'),
(2, 'App crashes when opening profile screen', 'Occurs on Android 13 devices.', 2, NULL, 'new', 'critical', '2024-03-10 16:00:00', '2024-03-10 16:00:00'),
(3, 'API endpoint /users returns 500 error', 'The /users endpoint fails intermittently.', 1, 1, 'resolved', 'high', '2024-02-20 09:30:00', '2024-03-08 17:00:00'),
(1, 'Typo in footer text', 'Copyright year is wrong.', 3, NULL, 'new', 'low', '2024-03-12 11:00:00', '2024-03-12 11:00:00');
INSERT INTO BugComments (bug_id, user_id, comment_text, commented_at) VALUES
(1, 1, 'Confirmed. Investigating CSS issue.', '2024-03-01 11:35:00'),
(2, 1, 'Working on fix. Related to localization logic.', '2024-03-06 09:05:00'),
(4, 1, 'Fix deployed. Closing this issue.', '2024-03-08 17:00:00'),
(1, 2, 'Still seeing this issue on Firefox 110.', '2024-03-09 10:00:00');
Tasks:
- Basic Index: Create a basic index on the
Bugs
table for thestatus
column, as filtering by status is very common. - Foreign Key Index: Create an index on the
Bugs
table for theproject_id
column to quickly find all bugs associated with a specific project. - Foreign Key Index: Create an index on the
Bugs
table for thereported_by_user_id
column. - Foreign Key Index (Nullable): Create an index on the
Bugs
table for theassigned_to_user_id
column. Note that this column can contain NULLs. - Multicolumn Index: Create a multicolumn index on the
Bugs
table for(project_id, status)
to efficiently filter bugs within a specific project by their status. - Multicolumn Index: Create another multicolumn index on the
Bugs
table for(assigned_to_user_id, status)
to help users quickly find their assigned bugs filtered by status. - Partial Index: Create a partial index on the
Bugs
table covering theupdated_at
column, but only for bugs that are not in ‘resolved’ or ‘closed’ status (i.e., active bugs). This optimizes queries looking for recently updated active issues.WHERE status NOT IN ('resolved', 'closed')
- Foreign Key Index (Comments): Create an index on the
BugComments
table for thebug_id
column to rapidly retrieve all comments for a specific bug. - Unique Index Explanation: The
Users
table hasUNIQUE
constraints onusername
andemail
. Explain why you typically don’t need to manually create basic B-tree indexes on these specific columns. - List and Drop Index: Use the
pg_indexes
system catalog view to list all indexes currently defined for theBugs
table. Identify and then drop the basic index created on thestatus
column in step 1.
Variant 16: Car Rental Agency
Scenario: You are managing the database for a car rental company. Fast lookups for available vehicles, customer rental histories, and vehicle locations are essential for smooth operations at the rental counters and for the online booking system.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS Rentals;
DROP TABLE IF EXISTS Cars;
DROP TABLE IF EXISTS Customers;
DROP TABLE IF EXISTS Locations;
-- Create the Locations table (where cars can be picked up/dropped off)
CREATE TABLE Locations (
location_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
city VARCHAR(100),
address VARCHAR(255),
phone_number VARCHAR(20)
);
-- Create the Customers table
CREATE TABLE Customers (
customer_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20),
driver_license_id VARCHAR(50) UNIQUE NOT NULL,
join_date DATE DEFAULT CURRENT_DATE
);
-- Create the Cars table
CREATE TABLE Cars (
car_id SERIAL PRIMARY KEY,
license_plate VARCHAR(15) UNIQUE NOT NULL,
make VARCHAR(50),
model VARCHAR(50),
year INT,
category VARCHAR(30), -- e.g., 'Sedan', 'SUV', 'Truck', 'Luxury'
status VARCHAR(20) DEFAULT 'available', -- 'available', 'rented', 'maintenance'
current_location_id INT REFERENCES Locations(location_id)
);
-- Create the Rentals table
CREATE TABLE Rentals (
rental_id SERIAL PRIMARY KEY,
car_id INT NOT NULL REFERENCES Cars(car_id),
customer_id INT NOT NULL REFERENCES Customers(customer_id),
pickup_location_id INT NOT NULL REFERENCES Locations(location_id),
dropoff_location_id INT REFERENCES Locations(location_id), -- Can be null initially
rental_start_date TIMESTAMP NOT NULL,
rental_end_date TIMESTAMP, -- Date expected or actual return
total_cost NUMERIC(8, 2),
actual_return_date TIMESTAMP -- NULL if not returned
);
-- Insert sample data
INSERT INTO Locations (name, city, address) VALUES
('Airport Branch', 'Metropolis', '1 Airport Rd'),
('Downtown Station', 'Metropolis', '123 Main St'),
('Westside Rentals', 'Gotham', '456 West Ave');
INSERT INTO Customers (first_name, last_name, email, phone, driver_license_id) VALUES
('Clark', 'Kent', 'clark.kent@dailyplanet.com', '555-1111', 'DL12345'),
('Lois', 'Lane', 'lois.lane@dailyplanet.com', '555-2222', 'DL67890'),
('Bruce', 'Wayne', 'bruce@waynecorp.com', '555-3333', 'DL54321');
INSERT INTO Cars (license_plate, make, model, year, category, status, current_location_id) VALUES
('SUPRMAN', 'Ford', 'Fusion', 2022, 'Sedan', 'available', 1),
('R3P0RT', 'Toyota', 'Camry', 2023, 'Sedan', 'rented', 1),
('BATM0BL', 'Lamborghini', 'Aventador', 2023, 'Luxury', 'available', 2),
('TRUTH', 'Honda', 'CRV', 2021, 'SUV', 'maintenance', 1),
('JUST1CE', 'Chevrolet', 'Silverado', 2022, 'Truck', 'available', 3);
INSERT INTO Rentals (car_id, customer_id, pickup_location_id, rental_start_date, rental_end_date) VALUES
(2, 2, 1, '2024-03-10 09:00:00', '2024-03-17 09:00:00'), -- Lois rented the Camry
(3, 3, 2, '2024-03-15 14:00:00', '2024-03-18 14:00:00'); -- Bruce rented the Lambo (let's assume it's rented now for the task)
-- Update car status for rented car
UPDATE Cars SET status = 'rented' WHERE car_id = 3;
Tasks:
- Basic Index: Create an index on the
Cars
table to speed up searches based on the car’smake
. - Unique Index Check: The
Customers
table already hasUNIQUE
constraints onemail
anddriver_license_id
. Explain what kind of indexes PostgreSQL likely created automatically for these columns. - Foreign Key Index: Create an index on the
Cars
table to efficiently find all cars currently located at a specificcurrent_location_id
. - Foreign Key Index: Create an index on the
Rentals
table to quickly retrieve all rentals associated with a specificcustomer_id
. - Foreign Key Index: Create an index on the
Rentals
table to quickly find the rental history for a specificcar_id
. - Multicolumn Index: Create a multicolumn index on the
Cars
table to optimize queries searching for cars of a specificcategory
andyear
. Ensurecategory
is the leading column. - Partial Index: Create a partial index on the
Cars
table for thecurrent_location_id
column, but only include cars where thestatus
is ‘available’. This helps optimize finding available cars at a specific location. - Index on Expression: Create an index on the
Customers
table based on the lowercase version of theemail
column to facilitate case-insensitive email lookups. - List Indexes: Use the
\d Rentals
meta-command (in psql or pgAdmin’s Query Tool SQL pane) to list all indexes currently associated with theRentals
table. - Drop Index: Remove the index created in step 1 (on
Cars.make
).
Variant 17: Subscription Service Management
Scenario: You are responsible for the database of a popular online streaming service. Efficiently managing user subscriptions, tracking plan details, and recording billing events are critical for business operations and user account management.
Database Schema:
-- Drop tables if they exist to start fresh
DROP TABLE IF EXISTS BillingEvents;
DROP TABLE IF EXISTS Subscriptions;
DROP TABLE IF EXISTS Plans;
DROP TABLE IF EXISTS ServiceUsers; -- Renamed from Users to avoid conflict with SQL keyword
-- Create the ServiceUsers table
CREATE TABLE ServiceUsers (
user_id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
full_name VARCHAR(150),
registration_date DATE DEFAULT CURRENT_DATE
);
-- Create the Plans table
CREATE TABLE Plans (
plan_id SERIAL PRIMARY KEY,
plan_name VARCHAR(100) UNIQUE NOT NULL, -- e.g., 'Basic', 'Premium', 'Family'
monthly_cost NUMERIC(6, 2) NOT NULL CHECK (monthly_cost >= 0),
features JSONB -- Store features like resolution, number of screens, etc.
);
-- Create the Subscriptions table
CREATE TABLE Subscriptions (
subscription_id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES ServiceUsers(user_id),
plan_id INT NOT NULL REFERENCES Plans(plan_id),
start_date DATE NOT NULL,
end_date DATE, -- NULL for ongoing, set for cancelled/expired
status VARCHAR(20) DEFAULT 'active', -- 'active', 'cancelled', 'expired', 'pending_payment'
auto_renew BOOLEAN DEFAULT TRUE
);
-- Create the BillingEvents table
CREATE TABLE BillingEvents (
event_id SERIAL PRIMARY KEY,
subscription_id INT NOT NULL REFERENCES Subscriptions(subscription_id),
event_type VARCHAR(30) NOT NULL, -- 'charge', 'refund', 'payment_failed'
event_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
amount NUMERIC(8, 2),
status VARCHAR(20) DEFAULT 'success' -- 'success', 'failed', 'pending'
);
-- Insert sample data
INSERT INTO ServiceUsers (username, email, full_name) VALUES
('neo', 'neo@matrix.net', 'Thomas Anderson'),
('trinity', 'trinity@matrix.net', 'Trinity'),
('morpheus', 'morpheus@nebuchadnezzar.org', 'Morpheus');
INSERT INTO Plans (plan_name, monthly_cost, features) VALUES
('Basic', 9.99, '{"resolution": "SD", "screens": 1}'),
('Standard', 15.99, '{"resolution": "HD", "screens": 2, "downloads": true}'),
('Premium', 19.99, '{"resolution": "UHD", "screens": 4, "downloads": true}');
INSERT INTO Subscriptions (user_id, plan_id, start_date, end_date, status, auto_renew) VALUES
(1, 2, '2023-01-15', NULL, 'active', TRUE), -- Neo, Standard
(2, 3, '2023-02-01', NULL, 'active', TRUE), -- Trinity, Premium
(3, 1, '2023-03-10', '2024-03-09', 'expired', FALSE), -- Morpheus, Basic (Expired)
(1, 3, '2022-11-01', '2022-11-30', 'expired', FALSE); -- Neo's old Premium sub
INSERT INTO BillingEvents (subscription_id, event_type, amount, status) VALUES
(1, 'charge', 15.99, 'success'), -- Neo's recent charge
(2, 'charge', 19.99, 'success'), -- Trinity's recent charge
(3, 'charge', 9.99, 'success'); -- Morpheus' last charge before expiry
Tasks:
- Basic Index: Create an index on the
Plans
table to allow for faster lookups based onplan_name
. - Unique Index Consideration: The
ServiceUsers
table hasUNIQUE
constraints onusername
andemail
. What type of index is automatically created to enforce these, and what is its secondary benefit? - Foreign Key Index: Create an index on the
Subscriptions
table to quickly find all subscriptions belonging to a specificuser_id
. - Foreign Key Index: Create an index on the
Subscriptions
table to quickly find all users subscribed to a specificplan_id
. - Foreign Key Index: Create an index on the
BillingEvents
table to efficiently retrieve all billing events related to a specificsubscription_id
. - Multicolumn Index: Create a multicolumn index on the
BillingEvents
table to optimize queries filtering byevent_type
and then byevent_date
.event_type
should be the leading column. - Partial Index: Create a partial index on the
Subscriptions
table covering theend_date
column, but only for subscriptions where thestatus
is ‘active’ andauto_renew
is true. This helps identify active, auto-renewing subscriptions for processing renewals. - Index on Expression: Create an index on the
ServiceUsers
table using theLOWER()
function on theusername
column to enable efficient case-insensitive username searches. - Reindex Table: Rebuild all indexes on the
Subscriptions
table to ensure optimal performance after numerous status updates or renewals might have occurred. - List and Drop Index: Use the
pg_indexes
system view to list all indexes on theBillingEvents
table. Identify and then drop the multicolumn index created in step 6 (event_type
,event_date
).
Submission Instructions
- Create a new Google Document. Example
- Submit Your Google Doc Link (915-23 KII): Google Sheet
- Submit Your Google Doc Link (953-23 AXI): Google Sheet