Phase 6 – Complex DB Reports (SQL, Stored Procedures, Relational Algebra)
Overview
In this phase we demonstrate how to extract, analyze and summarize data from the Wedding Planner database using advanced SQL. We focus on generating complex reports across multiple related tables, and implementing reusable logic through stored procedures and views.
These techniques are important because in a real system the database is not used only for storing data, but also for producing meaningful insights (guest statistics, cost reports, utilization reports, timelines, etc.).
What we cover in this phase
- Complex reports using JOINs, GROUP BY and aggregate functions
- Stored procedures for reusable database logic
- Views for simplified access to frequently needed reports
- Relational Algebra (theoretical foundation behind SQL)
- Grouping and filtering techniques
- Cost analysis and capacity utilization examples
Implementation / Examples
1) Complex Reports
Complex reports combine data from multiple tables and return analytical information that is useful for managing weddings. In our Wedding Planner system, reports are useful for guest status tracking, cost breakdown, scheduling and venue usage.
Example 1: Total guests and RSVP status per wedding
This query returns the total number of guests per wedding, and how many RSVPs are CONFIRMED vs CANCELLED.
SELECT
w.wedding_id,
w.date AS wedding_date,
COUNT(DISTINCT g.guest_id) AS total_guests,
COUNT(CASE WHEN r.status = 'CONFIRMED' THEN 1 END) AS confirmed_guests,
COUNT(CASE WHEN r.status = 'CANCELLED' THEN 1 END) AS cancelled_guests
FROM wedding w
LEFT JOIN guest g ON w.wedding_id = g.wedding_id
LEFT JOIN event e ON w.wedding_id = e.wedding_id
LEFT JOIN event_rsvp r ON e.event_id = r.event_id AND g.guest_id = r.guest_id
GROUP BY w.wedding_id, w.date;
*Purpose:* Helps the wedding owner see how many guests are invited and their RSVP status.
Example 2: Costs per wedding (venue + band + photographer)
This report computes the cost of a wedding by summing the cost of booked providers.
SELECT
w.wedding_id,
w.date,
COALESCE(SUM(vb.price), 0) AS venue_cost,
COALESCE(SUM(EXTRACT(EPOCH FROM (bb.end_time - bb.start_time))/3600 * b.price_per_hour), 0) AS band_cost,
COALESCE(SUM(EXTRACT(EPOCH FROM (pb.end_time - pb.start_time))/3600 * p.price_per_hour), 0) AS photographer_cost
FROM wedding w
LEFT JOIN venue_booking vb ON w.wedding_id = vb.wedding_id
LEFT JOIN band_booking bb ON w.wedding_id = bb.wedding_id
LEFT JOIN band b ON bb.band_id = b.band_id
LEFT JOIN photographer_booking pb ON w.wedding_id = pb.wedding_id
LEFT JOIN photographer p ON pb.photographer_id = p.photographer_id
GROUP BY w.wedding_id, w.date;
*Purpose:* Gives a clear financial summary for budgeting and comparing providers.
Example 3: Venue utilization (capacity report)
This query checks how many guests are seated, and how many free seats are still available at the booked venue.
SELECT
v.name AS venue_name,
v.capacity,
w.wedding_id,
COUNT(a.guest_id) AS seated_guests,
(v.capacity - COUNT(a.guest_id)) AS free_seats
FROM venue v
JOIN venue_booking vb ON v.venue_id = vb.venue_id
JOIN wedding w ON vb.wedding_id = w.wedding_id
LEFT JOIN attendance a ON a.event_id IN (
SELECT event_id FROM event WHERE wedding_id = w.wedding_id
)
GROUP BY v.name, v.capacity, w.wedding_id;
*Purpose:* Useful to see if the wedding has exceeded the venue capacity or still has room.
Example 4: Temporal distribution of events
This query returns the schedule of events ordered by date and time.
SELECT
w.wedding_id,
e.event_type,
e.date,
e.start_time,
e.end_time,
EXTRACT(EPOCH FROM (e.end_time - e.start_time))/3600 AS duration_hours
FROM wedding w
JOIN event e ON w.wedding_id = e.wedding_id
ORDER BY e.date, e.start_time;
*Purpose:* Helps planning timelines and checking event overlaps in the schedule.
2) Stored Procedures
Stored procedures allow us to encapsulate database logic into reusable functions that can be called when needed. They reduce repetition and help organize logic for reporting and automation.
Example 1: Total wedding cost
This procedure calculates the full total cost of a wedding (venue + band + photographer).
CREATE OR REPLACE PROCEDURE wedding_total_cost(
IN p_wedding_id INT,
OUT total_cost NUMERIC
)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT
COALESCE(SUM(vb.price),0)
+ COALESCE(SUM(EXTRACT(EPOCH FROM (bb.end_time - bb.start_time))/3600 * b.price_per_hour),0)
+ COALESCE(SUM(EXTRACT(EPOCH FROM (pb.end_time - pb.start_time))/3600 * p.price_per_hour),0)
INTO total_cost
FROM wedding w
LEFT JOIN venue_booking vb ON w.wedding_id = vb.wedding_id
LEFT JOIN band_booking bb ON w.wedding_id = bb.wedding_id
LEFT JOIN band b ON bb.band_id = b.band_id
LEFT JOIN photographer_booking pb ON w.wedding_id = pb.wedding_id
LEFT JOIN photographer p ON pb.photographer_id = p.photographer_id
WHERE w.wedding_id = p_wedding_id;
END;
$$;
*Purpose:* Gives one clear number for budgeting and reports.
