SQL Analysis and Tableau Vizualization for Courierly company

About the company: Courierly is a company that connects vendors to drivers for delivering packages. A vendor can place an order request for a package pick up, and drivers that are employed by the Courierly app can then accept or reject the order request. Vendors can either be larger corporate entities, small businesses, or individuals.

Objective: To analyze driver performance and engagement as well as vendor and order insights.

Applied skills: Excel SQL SQLite Tableau

Stakeholder questions:

  1. Which 3 drivers have completed the most orders over the last 6 months of 2024?
  2. How do payouts compare for drivers during promotion periods versus non-promotion periods?
  3. How many drivers joined in the 2024, and how many of them are still active? A driver is active if they have completed any orders within the last 4 months of 2024.
  4. Do drivers with Courierly stickers in their cars (Sticker = Y) complete more orders than those without?
  5. Which type of vendors (Corporate vs. Personal) generates the most revenue for Courierly?
  6. What is the average total distance per order, and how does it differ between Corporate and Personal vendors?
  7. What percentage of orders are canceled or rejected, and are there any patterns based on vendor type or order distance?

Answers

Which 3 drivers have completed the most orders over the last 6 months of 2024?

Over the past 6 months from today (December 29, 2024), the top 3 drivers who completed the most orders are:

SQL query
                
    SELECT d.driverid, d.name, COUNT(o.OrderID) AS [Orders Number] 
    FROM Drivers d
    LEFT JOIN Order_Status os ON os.DriverID = d.DriverID
    LEFT JOIN Orders o ON o.OrderID = os.OrderID
    WHERE os.OrderStatus = 'Completed' 
    AND o.Order_Date BETWEEN datetime('2024-12-31', 'start of month', '+30 days', '-6 month') 
    AND date('2024-12-31')
    GROUP BY d.driverid
    ORDER BY COUNT(o.OrderID) DESC
                
            

How do payouts compare for drivers during promotion periods versus non-promotion periods?

Payouts were compared among drivers who participated in both promo and regular periods based on average payout data for each period. The results were ordered based on the highest payout during the promo period. The driver with the highest payout earned 172.69% more during the promo period than the regular. The driver with the lowest payout made 82.71% less during the promo period than the regular. On average, drivers earned 10.24% more during the promo period than regular.

SQL query
                  
    /* Average single value for promo and regular periods and percentage change between payouts */
    select round(avg(avg_promo_payout),2) as avg_promo_payout, round(avg(avg_reg_payout),2) as avg_regular_payout, round(100.0 * (avg(avg_promo_payout) - avg(avg_reg_payout)) / avg(avg_reg_payout),2) || '%' as change_percentage from (select distinct p.DriverID, 
    /* Average payout values for each period and percentage change per driver */
    round(avg(iif(o.order_date Between pr.Promotion_Begin and pr.Promotion_End and os.OrderStatus = 'Completed', p.price_payout, null)),2) as avg_promo_payout,
    round(avg(iif(o.order_date < pr.Promotion_Begin or o.order_date > pr.Promotion_End and os.OrderStatus = 'Completed', p.price_payout, null)),2) as avg_reg_payout,
    round(100.0 * (avg(iif(o.order_date Between pr.Promotion_Begin and pr.Promotion_End and os.OrderStatus = 'Completed', p.price_payout, null)) - avg(iif(o.order_date < pr.Promotion_Begin or o.order_date > pr.Promotion_End and os.OrderStatus = 'Completed', p.price_payout, null)))/avg(iif(o.order_date < pr.Promotion_Begin or o.order_date > pr.Promotion_End and os.OrderStatus = 'Completed', p.price_payout, null)),2) || '%' as change_percentage 
    from payout p
    inner join promotions pr on pr.DriverID = p.DriverID
    inner join orders o on o.OrderID = p.OrderID
    inner join Order_Status os on os.OrderID = p.OrderID
    group by p.DriverID
    having avg_promo_payout is not null and avg_reg_payout is not null
    order by avg_promo_payout desc)    
                  
              

How many drivers joined in the 2024, and how many of them are still active? A driver is active if they have completed any orders within the last 4 months of 2024.

During the last 2024 year, 461 drivers joined Courierly. All of them are still active in the company, as they have completed orders within the last 4 months.

SQL Query
                    
    with drivers_joined_2024 as (select driverid, name, count(driverid) over (partition by strftime('%Y', date_of_joining)) as joined_2024 from Drivers
    where strftime('%Y', date_of_joining) = '2024')
                        
    select count(distinct d.driverid) from drivers_joined_2024 d
    left join Order_Status os on os.driverid = d.driverid
    left Join Orders o on o.OrderID = os.OrderID
    where o.order_date >= datetime('2024-12-31','start of month', '+30 days', '-4 month') and os.OrderStatus = 'Completed'                            
                    
                

Do drivers with Courierly stickers in their cars (Sticker = Y) complete more orders than those without?

Yes, drivers with company stickers complete more orders than those without. For reference, drivers without stickers completed 22496 orders compared to the drivers with stickers. The latter completed 26129 orders, which is 3633 more orders than those without stickers.

SQL Query
                      
    with stickers as (select count(iif(d.[Sticker_(Y/N)] = 'Y', os.OrderID, null)) as orders_with_stickers, count(iif(d.[Sticker_(Y/N)] = 'N', os.OrderID, null)) as orders_without_stickers from Order_Status os
    left join Drivers d on d.DriverID = os.DriverID
    where os.OrderStatus = 'Completed')
                        
    select orders_with_stickers, orders_without_stickers, (orders_with_stickers - orders_without_stickers) as difference from stickers                                       
                      
                  

Which type of vendors (Corporate vs. Personal) generates the most revenue for Courierly?

Corporate vendors generate more revenue than personal ones. Personal vendors generated 2831441.03, which is 22.23% of the total revenue, while corporate - 9908430.55, which is 77.77% of the total revenue.

SQL Query
                
    with sorted_vendors as (select sum(iif(v.Vendor_Type = 'Personal', Price, null)) as personal_total_revenue, sum(iif(v.Vendor_Type = 'Corporate', Price, null)) as corporate_total_revenue from Vendors v
    left join Orders o on o.VendorID = v.VendorID)
                            
    select personal_total_revenue, round(personal_total_revenue/(personal_total_revenue + corporate_total_revenue) * 100,2) || '%'  as personal_percentage, corporate_total_revenue, round(corporate_total_revenue/(personal_total_revenue + corporate_total_revenue) * 100,2) || '%'  as corporate_percentage from sorted_vendors                                                         
                
            

What is the average total distance per order, and how does it differ between Corporate and Personal vendors?

The average distance per order from personal vendors is 126.41, while from corporate vendors - 126.5. This minor difference shows that distance does not depend on the vendor type.

SQL Query
                
    with avg_distance as (select avg(iif(v.Vendor_Type = 'Personal',o.total_distance, null)) as personal_average_distance, avg(iif(v.Vendor_Type = 'Corporate',o.total_distance, null)) as corporate_average_distance from Orders o
    left join Vendors v on v.VendorID = o.VendorID)
                    
    select round(personal_average_distance, 2) as personal, round(corporate_average_distance,2) as corporate from avg_distance
                
            

What percentage of orders are canceled or rejected, and are there any patterns based on vendor type or order distance?

The total percentage of canceled or rejected orders is 44.02%, which is slightly less than half of all orders. Among them, the cancellation percentage from corporate vendors is 78.08%, and personal - 21.92%. Based on the distance, the amount of canceled orders with a distance range from minimal to average makes 49.45%, and from average to maximal - 50.55%. Based on the above calculations, the largest part of cancellations/rejections comes from orders from corporate vendors (almost 80%). Distance doesn’t affect cancellations/rejections significantly, as the percentage of minimal to average and average to maximal distances is almost equal.

SQL Query
                  
    /* Number of canceled orders */
    with cancelled_orders as (select o.OrderID, o.Total_Distance, o.VendorID from Orders o
    left join Order_Status os on os.OrderID = o.OrderID
    where os.OrderStatus in ('Cancelled', 'Rejected')),
    /* The total percentage of cancelled/rejected orders*/
    percentage_of_cancellations as (select round(100.0 * (count(co.OrderID))/(select count(orderid) from Orders),2) || '%' from cancelled_orders co)
                    
    /* Percentage of cancellations among canceled orders based on different criteria */
    select round(100.0 * count(iif(v.Vendor_Type = 'Corporate', o.orderid, null))/ count(o.OrderID), 2) || '%' as percent_corporate,
    round(100.0 * count(iif(v.Vendor_Type = 'Personal', o.orderid, null))/ count(o.OrderID), 2) || '%' as percent_personal,
    round(100.0 * count(iif(o.Total_Distance <= (select avg(total_distance) from Orders), o.orderid, null))/ count(o.OrderID), 2) || '%' as min_to_avg_distance,
    round(100.0 * count(iif(o.Total_Distance > (select avg(total_distance) from Orders), o.orderid, null))/ count(o.OrderID), 2) || '%' as avg_to_max_distance from cancelled_orders o
    left join Vendors v on v.VendorID = o.VendorID