wiki:AnalyticalStatisticalQuerying

Version 2 (modified by 221164, 9 days ago) ( diff )

--

Analytical and Statistical Queries

Daily Revenue

SELECT 
    DATE(timestamp) AS payment_date, 
    SUM(amount) AS total_revenue
FROM payments
GROUP BY DATE(timestamp)
ORDER BY payment_date;

Daily Order Count and Average Order Value

SELECT 
    DATE(o.datetime) AS order_date, 
    COUNT(o.id) AS total_orders, 
    AVG(p.amount) AS avg_order_value
FROM orders o
JOIN payments p ON o.id = p.order_id
GROUP BY DATE(o.datetime)
ORDER BY order_date;

Order Distribution by Order Category

SELECT
    c.name AS category,
    COUNT(oi.id) AS total_items_ordered
FROM order_items oi
JOIN products p ON oi.product_id = p.id
JOIN categories c ON p.category_id = c.id
GROUP BY c.name
ORDER BY total_items_ordered DESC;

Top 10 Best-Selling Products

SELECT
    p.name AS product,
    SUM(oi.quantity) AS total_quantity_sold
FROM order_items oi
JOIN products p ON oi.product_id = p.id
GROUP BY p.name
ORDER BY total_quantity_sold DESC
LIMIT 10;

Online Orders vs. Tab Orders Count

SELECT 'Online Orders' AS order_type, COUNT(*) AS total_orders
FROM online_orders
UNION ALL
SELECT 'Tab Orders' AS order_type, COUNT(*) AS total_orders
FROM tab_orders;

Revenue Split: Online vs Tab Orders

SELECT
    'Online Orders' AS order_type,
    SUM(p.amount) AS total_revenue
FROM orders o
JOIN payments p ON o.id = p.order_id
JOIN online_orders oo ON o.id = oo.order_id;

SELECT
    'Tab Orders' AS order_type,
    SUM(p.amount) AS total_revenue
FROM orders o
JOIN payments p ON o.id = p.order_id
JOIN tab_orders tord ON o.id = tord.order_id;

Average Shift Duration per Manager

SELECT
    manager_id,
    AVG(EXTRACT(EPOCH FROM (end_time - start_time)) / 3600) AS avg_shift_duration_hours
FROM shifts
GROUP BY manager_id;

Orders Managed by Each Front Staff

SELECT
    fs.employee_id,
    COUNT(tord.order_id) AS total_orders_managed
FROM tab_orders tord
JOIN front_staff fs ON tord.front_staff_id = fs.employee_id
GROUP BY fs.employee_id
ORDER BY total_orders_managed DESC;

Average Tip Percentage per Staff Role

SELECT
    sr.name AS staff_role,
    AVG(fs.tip_percent) AS avg_tip_percent
FROM front_staff fs
JOIN staff_roles sr ON fs.staff_role_id = sr.id
GROUP BY sr.name;

Inventory Turnover Ratio per Product

SELECT
    p.name AS product,
    inv.quantity AS current_inventory,
    SUM(oi.quantity) AS total_quantity_ordered,
    CASE
        WHEN inv.quantity = 0 THEN NULL
        ELSE SUM(oi.quantity)::decimal / inv.quantity
    END AS turnover_ratio
FROM products p
JOIN inventories inv ON p.id = inv.product_id
JOIN order_items oi ON p.id = oi.product_id
GROUP BY p.name, inv.quantity
ORDER BY turnover_ratio DESC;

Most Popular Table by Reservations

SELECT
    table_number,
    COUNT(*) AS reservation_count
FROM frontstaff_managed_reservations
GROUP BY table_number
ORDER BY reservation_count DESC
LIMIT 1;

Reservations by Day of Week

SELECT
    EXTRACT(DOW FROM datetime) AS day_of_week,  -- 0=Sunday, 1=Monday, etc.
    COUNT(*) AS total_reservations
FROM reservations
GROUP BY day_of_week
ORDER BY total_reservations DESC;

Stored procedure

CREATE OR REPLACE FUNCTION get_analytics_stats(
    p_start_date DATE,
    p_end_date DATE
)
RETURNS JSON AS $$
DECLARE
    result JSON;
BEGIN
    SELECT json_build_object(
        'dailyRevenue', (
            SELECT json_agg(r)
            FROM (
                SELECT DATE(timestamp) AS payment_date, SUM(amount) AS total_revenue
                FROM payments
                WHERE DATE(timestamp) BETWEEN p_start_date AND p_end_date
                GROUP BY DATE(timestamp)
                ORDER BY payment_date
            ) r
        ),
        'dailyOrders', (
            SELECT json_agg(r)
            FROM (
                SELECT DATE(o.datetime) AS order_date, COUNT(o.id) AS total_orders, AVG(p.amount) AS avg_order_value
                FROM orders o
                JOIN payments p ON o.id = p.order_id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY DATE(o.datetime)
                ORDER BY order_date
            ) r
        ),
        'orderDistribution', (
            SELECT json_agg(r)
            FROM (
                SELECT c.name AS category, COUNT(oi.id) AS total_items_ordered
                FROM order_items oi
                JOIN products p ON oi.product_id = p.id
                JOIN categories c ON p.category_id = c.id
                JOIN orders o ON o.id = oi.order_id  -- filter by order date
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY c.name
                ORDER BY total_items_ordered DESC
            ) r
        ),
        'topProducts', (
            SELECT json_agg(r)
            FROM (
                SELECT p.name AS product, SUM(oi.quantity) AS total_quantity_sold
                FROM order_items oi
                JOIN products p ON oi.product_id = p.id
                JOIN orders o ON o.id = oi.order_id  -- apply date filter
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY p.name
                ORDER BY total_quantity_sold DESC
                LIMIT 10
            ) r
        ),
        'onlineVsTabOrders', (
            SELECT json_agg(r)
            FROM (
                SELECT 'Online Orders' AS order_type, COUNT(*) AS total_orders
                FROM online_orders oo
                JOIN orders o ON oo.order_id = o.id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                UNION ALL
                SELECT 'Tab Orders' AS order_type, COUNT(*) AS total_orders
                FROM tab_orders tord
                JOIN orders o ON tord.order_id = o.id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
            ) r
        ),
        'revenueSplit', (
            SELECT json_agg(r)
            FROM (
                SELECT 'Online Orders' AS order_type, SUM(p.amount) AS total_revenue
                FROM orders o
                JOIN payments p ON o.id = p.order_id
                JOIN online_orders oo ON o.id = oo.order_id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                UNION ALL
                SELECT 'Tab Orders' AS order_type, SUM(p.amount) AS total_revenue
                FROM orders o
                JOIN payments p ON o.id = p.order_id
                JOIN tab_orders tord ON o.id = tord.order_id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
            ) r
        ),
        'avgShiftDuration', (
            SELECT json_agg(r)
            FROM (
                SELECT manager_id,
                       AVG(EXTRACT(EPOCH FROM (end_time - start_time)) / 3600) AS avg_shift_duration_hours
                FROM shifts
                WHERE DATE(start_time) BETWEEN p_start_date AND p_end_date
                GROUP BY manager_id
            ) r
        ),
        'ordersByFrontStaff', (
            SELECT json_agg(r)
            FROM (
                SELECT fs.employee_id, COUNT(tord.order_id) AS total_orders_managed
                FROM tab_orders tord
                JOIN front_staff fs ON tord.front_staff_id = fs.employee_id
                JOIN orders o ON tord.order_id = o.id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY fs.employee_id
                ORDER BY total_orders_managed DESC
            ) r
        ),
        'avgTipPercentage', (
            SELECT json_agg(r)
            FROM (
                SELECT sr.name AS staff_role, AVG(fs.tip_percent) AS avg_tip_percent
                FROM front_staff fs
                JOIN staff_roles sr ON fs.staff_role_id = sr.id
                GROUP BY sr.name
            ) r
        ),
        'inventoryTurnover', (
            SELECT json_agg(r)
            FROM (
                SELECT p.name AS product, inv.quantity AS current_inventory,
                       SUM(oi.quantity) AS total_quantity_ordered,
                       CASE WHEN inv.quantity = 0 THEN NULL ELSE SUM(oi.quantity)::decimal / inv.quantity END AS turnover_ratio
                FROM products p
                JOIN inventories inv ON p.id = inv.product_id
                JOIN order_items oi ON p.id = oi.product_id
                JOIN orders o ON o.id = oi.order_id
                WHERE DATE(o.datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY p.name, inv.quantity
                ORDER BY turnover_ratio DESC
            ) r
        ),
        'mostPopularTable', (
            SELECT json_build_object(
                'table_number', table_number,
                'reservation_count', reservation_count
            )
            FROM (
                SELECT table_number, COUNT(*) AS reservation_count
                FROM frontstaff_managed_reservations
                WHERE DATE(datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY table_number
                ORDER BY reservation_count DESC
                LIMIT 1
            ) sub
        ),
        'reservationsByDayOfWeek', (
            SELECT json_agg(r)
            FROM (
                SELECT EXTRACT(DOW FROM datetime) AS day_of_week, COUNT(*) AS total_reservations
                FROM reservations
                WHERE DATE(datetime) BETWEEN p_start_date AND p_end_date
                GROUP BY day_of_week
                ORDER BY total_reservations DESC
            ) r
        )
    ) INTO result;
    
    RETURN result;
END;
$$ LANGUAGE plpgsql;
SELECT get_analytics_stats('2025-01-01', '2025-01-31');
Note: See TracWiki for help on using the wiki.