wiki:Advanced Application Development

Version 3 (modified by 221531, 3 days ago) ( diff )

--

Report Tables

Main Restaurant Report Summary Table

CREATE TABLE restaurant_weekly_report (

report_id SERIAL PRIMARY KEY, restaurant_id INT NOT NULL, report_week DATE NOT NULL, -- Monday of the week week_number INT NOT NULL, -- Week 1, 2, or 3 (most recent)

-- Order Statistics total_orders INTEGER DEFAULT 0, completed_orders INTEGER DEFAULT 0, cancelled_orders INTEGER DEFAULT 0,

-- Financial Metrics gross_revenue DECIMAL(12,2) DEFAULT 0.00, net_revenue DECIMAL(12,2) DEFAULT 0.00, -- After platform commission average_order_value DECIMAL(10,2) DEFAULT 0.00, total_items_sold INTEGER DEFAULT 0,

-- Operational Metrics avg_preparation_time_minutes DECIMAL(8,2) DEFAULT 0.00, peak_hour INTEGER, -- Hour with most orders busiest_day INTEGER, -- Day of week (0=Sunday, 6=Saturday)

-- Performance Indicators completion_rate DECIMAL(5,2) DEFAULT 0.00, -- % of orders completed customer_satisfaction DECIMAL(3,2) DEFAULT 0.00, -- Placeholder for ratings orders_per_hour DECIMAL(8,2) DEFAULT 0.00,

-- Timestamps generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT fk_weekly_report_restaurant FOREIGN KEY (restaurant_id) REFERENCES restaurant(restaurant_id), CONSTRAINT uq_restaurant_week UNIQUE (restaurant_id, report_week)

);

Popular Items Report Table

CREATE TABLE restaurant_popular_items (

report_id SERIAL PRIMARY KEY, restaurant_id INT NOT NULL, report_week DATE NOT NULL, item_id INT NOT NULL, item_name VARCHAR(100),

times_ordered INTEGER DEFAULT 0, total_quantity INTEGER DEFAULT 0, total_revenue DECIMAL(10,2) DEFAULT 0.00, avg_price DECIMAL(8,2) DEFAULT 0.00, popularity_rank INTEGER,

generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT fk_popular_items_restaurant FOREIGN KEY (restaurant_id) REFERENCES restaurant(restaurant_id), CONSTRAINT fk_popular_items_item FOREIGN KEY (item_id) REFERENCES item(item_id)

);

Daily Breakdown Table

CREATE TABLE restaurant_daily_breakdown (

breakdown_id SERIAL PRIMARY KEY, restaurant_id INT NOT NULL, report_date DATE NOT NULL, day_of_week INTEGER, -- 0=Sunday, 6=Saturday

daily_orders INTEGER DEFAULT 0, daily_revenue DECIMAL(10,2) DEFAULT 0.00, daily_items_sold INTEGER DEFAULT 0, avg_order_value DECIMAL(8,2) DEFAULT 0.00,

-- Hourly breakdown (JSON format for flexibility) hourly_orders JSONB,

generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT fk_daily_breakdown_restaurant FOREIGN KEY (restaurant_id) REFERENCES restaurant(restaurant_id), CONSTRAINT uq_restaurant_daily UNIQUE (restaurant_id, report_date)

);

Comparative Analysis Table (Week Over Week)

CREATE TABLE restaurant_trend_analysis (

trend_id SERIAL PRIMARY KEY, restaurant_id INT NOT NULL, analysis_date DATE DEFAULT CURRENT_DATE,

-- 3-week trends week1_revenue DECIMAL(10,2), -- Most recent week week2_revenue DECIMAL(10,2), week3_revenue DECIMAL(10,2),

week1_orders INTEGER, week2_orders INTEGER, week3_orders INTEGER,

-- Trend indicators revenue_trend VARCHAR(20), -- 'INCREASING', 'DECREASING', 'STABLE' order_trend VARCHAR(20),

-- Growth rates revenue_growth_rate DECIMAL(8,2), -- Week over week % order_growth_rate DECIMAL(8,2),

-- Performance alerts performance_alerts JSONB, recommendations JSONB,

generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT fk_trend_analysis_restaurant FOREIGN KEY (restaurant_id) REFERENCES restaurant(restaurant_id)

);

Performance Metrics Table

CREATE TABLE performance_metrics (

metric_id SERIAL PRIMARY KEY, restaurant_id INT NOT NULL, metric_type VARCHAR(50), metric_value DECIMAL(8,2), recorded_at TIMESTAMP, CONSTRAINT fk_performance_metrics_restaurant FOREIGN KEY (restaurant_id) REFERENCES RESTAURANT(restaurant_id)

);

Audit Table for Orders

CREATE TABLE audit_orders (

audit_id SERIAL PRIMARY KEY, order_id INT, operation VARCHAR(50), new_status VARCHAR(50), changed_by VARCHAR(50), change_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP

);

Utility Functions


Get Week Start Function

CREATE OR REPLACE FUNCTION get_week_start(input_date DATE)

RETURNS DATE AS $$

BEGIN

RETURN input_date - INTERVAL '1 day' * EXTRACT(DOW FROM input_date);

END; $$ LANGUAGE plpgsql;

Get Week Number Function

CREATE OR REPLACE FUNCTION get_week_number(input_date DATE)

RETURNS INTEGER AS $$

DECLARE

week_start DATE; current_week_start DATE;

BEGIN

week_start := get_week_start(input_date); current_week_start := get_week_start(CURRENT_DATE);

RETURN CASE

WHEN week_start = current_week_start THEN 1 WHEN week_start = current_week_start - INTERVAL '7 days' THEN 2 WHEN week_start = current_week_start - INTERVAL '14 days' THEN 3 ELSE 0 -- Outside 3-week window

END;

END; $$ LANGUAGE plpgsql;

Main Report Generation Function

CREATE OR REPLACE FUNCTION generate_restaurant_weekly_report(p_restaurant_id INT, p_target_date DATE DEFAULT CURRENT_DATE)

RETURNS void AS $$

DECLARE

week_start DATE; week_end DATE; week_num INTEGER;

-- Variables for calculations v_total_orders INTEGER; v_completed_orders INTEGER; v_cancelled_orders INTEGER; v_gross_revenue DECIMAL(12,2); v_net_revenue DECIMAL(12,2); v_avg_order_value DECIMAL(10,2); v_total_items_sold INTEGER; v_avg_prep_time DECIMAL(8,2); v_peak_hour INTEGER; v_busiest_day INTEGER; v_completion_rate DECIMAL(5,2); v_orders_per_hour DECIMAL(8,2);

commission_rate DECIMAL(5,4) := 0.15; -- 15% platform fee

BEGIN

-- Calculate week boundaries week_start := get_week_start(p_target_date); week_end := week_start + INTERVAL '6 days'; week_num := get_week_number(p_target_date);

-- Skip if outside 3-week window IF week_num = 0 THEN

RETURN;

END IF;

-- Calculate order statistics SELECT

COUNT(*), COUNT(*) FILTER (WHERE order_status = 'delivered'), COUNT(*) FILTER (WHERE order_status = 'cancelled')

INTO v_total_orders, v_completed_orders, v_cancelled_orders FROM orders WHERE restaurant_id = p_restaurant_id

AND order_date::date BETWEEN week_start AND week_end;

-- Calculate financial metrics SELECT

COALESCE(SUM(total_amount), 0), COALESCE(SUM(total_amount * (1 - commission_rate)), 0), COALESCE(AVG(total_amount), 0)

INTO v_gross_revenue, v_net_revenue, v_avg_order_value FROM orders WHERE restaurant_id = p_restaurant_id

AND order_date::date BETWEEN week_start AND week_end AND order_status = 'delivered';

-- Calculate total items sold SELECT COALESCE(SUM(oi.quantity), 0) INTO v_total_items_sold FROM order_items oi

JOIN orders o ON oi.order_id = o.order_id

WHERE o.restaurant_id = p_restaurant_id

AND o.order_date::date BETWEEN week_start AND week_end AND o.order_status = 'delivered';

-- Calculate average preparation time (using performance metrics if available) SELECT COALESCE(AVG(metric_value), 0) INTO v_avg_prep_time FROM performance_metrics pm WHERE pm.restaurant_id = p_restaurant_id

AND pm.metric_type = 'prep_time_minutes' AND pm.recorded_at::date BETWEEN week_start AND week_end;

-- Find peak hour SELECT EXTRACT(hour FROM order_date) INTO v_peak_hour FROM orders WHERE restaurant_id = p_restaurant_id

AND order_date::date BETWEEN week_start AND week_end

GROUP BY EXTRACT(hour FROM order_date) ORDER BY COUNT(*) DESC LIMIT 1;

-- Find busiest day of week SELECT EXTRACT(dow FROM order_date) INTO v_busiest_day FROM orders WHERE restaurant_id = p_restaurant_id

AND order_date::date BETWEEN week_start AND week_end

GROUP BY EXTRACT(dow FROM order_date) ORDER BY COUNT(*) DESC LIMIT 1;

-- Calculate completion rate v_completion_rate := CASE

WHEN v_total_orders > 0 THEN

ROUND((v_completed_orders::DECIMAL / v_total_orders::DECIMAL) * 100, 2)

ELSE 0

END;

-- Calculate orders per hour (during operating hours) WITH operating_hours AS (

SELECT

EXTRACT(EPOCH FROM (closing_time - opening_time))/3600 * 7 as total_hours_week

FROM restaurant WHERE restaurant_id = p_restaurant_id

) SELECT CASE

WHEN oh.total_hours_week > 0 THEN v_total_orders::DECIMAL / oh.total_hours_week ELSE 0

END INTO v_orders_per_hour FROM operating_hours oh;

-- Insert or update the weekly report INSERT INTO restaurant_weekly_report (

restaurant_id, report_week, week_number, total_orders, completed_orders, cancelled_orders, gross_revenue, net_revenue, average_order_value, total_items_sold, avg_preparation_time_minutes, peak_hour, busiest_day, completion_rate, orders_per_hour, last_updated

) VALUES (

p_restaurant_id, week_start, week_num, v_total_orders, v_completed_orders, v_cancelled_orders, v_gross_revenue, v_net_revenue, v_avg_order_value, v_total_items_sold, v_avg_prep_time, v_peak_hour, v_busiest_day, v_completion_rate, v_orders_per_hour, CURRENT_TIMESTAMP

) ON CONFLICT (restaurant_id, report_week) DO UPDATE SET

total_orders = EXCLUDED.total_orders, completed_orders = EXCLUDED.completed_orders, cancelled_orders = EXCLUDED.cancelled_orders, gross_revenue = EXCLUDED.gross_revenue, net_revenue = EXCLUDED.net_revenue, average_order_value = EXCLUDED.average_order_value, total_items_sold = EXCLUDED.total_items_sold, avg_preparation_time_minutes = EXCLUDED.avg_preparation_time_minutes, peak_hour = EXCLUDED.peak_hour, busiest_day = EXCLUDED.busiest_day, completion_rate = EXCLUDED.completion_rate, orders_per_hour = EXCLUDED.orders_per_hour, last_updated = CURRENT_TIMESTAMP;

-- Generate popular items report PERFORM generate_popular_items_report(p_restaurant_id, week_start);

-- Generate daily breakdown PERFORM generate_daily_breakdown_report(p_restaurant_id, week_start, week_end);

END; $$ LANGUAGE plpgsql;

Popular Items Report Function

CREATE OR REPLACE FUNCTION generate_popular_items_report(p_restaurant_id INT, p_week_start DATE)

RETURNS void AS $$

BEGIN

-- Clear existing data for this week DELETE FROM restaurant_popular_items WHERE restaurant_id = p_restaurant_id AND report_week = p_week_start;

-- Insert top 10 popular items for the week INSERT INTO restaurant_popular_items (

restaurant_id, report_week, item_id, item_name, times_ordered, total_quantity, total_revenue, avg_price, popularity_rank

) WITH popular_items AS (

SELECT

i.item_id, i.name as item_name, COUNT(DISTINCT o.order_id) as times_ordered, SUM(oi.quantity) as total_quantity, SUM(oi.total_price) as total_revenue, AVG(oi.total_price / oi.quantity) as avg_price, ROW_NUMBER() OVER (ORDER BY COUNT(DISTINCT o.order_id) DESC) as popularity_rank

FROM orders o

JOIN order_items oi ON o.order_id = oi.order_id JOIN item i ON oi.item_id = i.item_id

WHERE o.restaurant_id = p_restaurant_id

AND o.order_date::date BETWEEN p_week_start AND p_week_start + INTERVAL '6 days' AND o.order_status = 'delivered'

GROUP BY i.item_id, i.name ORDER BY times_ordered DESC LIMIT 10

) SELECT

p_restaurant_id, p_week_start, item_id, item_name, times_ordered, total_quantity, total_revenue, avg_price, popularity_rank

FROM popular_items;

END; $$ LANGUAGE plpgsql;

Trend Analysis Function

CREATE OR REPLACE FUNCTION generate_trend_analysis(p_restaurant_id INT)

RETURNS void AS $$

DECLARE

week1_start DATE := get_week_start(CURRENT_DATE); week2_start DATE := week1_start - INTERVAL '7 days'; week3_start DATE := week1_start - INTERVAL '14 days';

w1_revenue DECIMAL(10,2); w2_revenue DECIMAL(10,2); w3_revenue DECIMAL(10,2); w1_orders INTEGER; w2_orders INTEGER; w3_orders INTEGER;

revenue_trend_val VARCHAR(20); order_trend_val VARCHAR(20); revenue_growth DECIMAL(8,2); order_growth DECIMAL(8,2);

alerts JSONB := '[]'::jsonb; recommendations JSONB := '[]'::jsonb;

BEGIN

-- Get weekly data SELECT gross_revenue, total_orders INTO w1_revenue, w1_orders FROM restaurant_weekly_report WHERE restaurant_id = p_restaurant_id AND report_week = week1_start;

SELECT gross_revenue, total_orders INTO w2_revenue, w2_orders FROM restaurant_weekly_report WHERE restaurant_id = p_restaurant_id AND report_week = week2_start;

SELECT gross_revenue, total_orders INTO w3_revenue, w3_orders FROM restaurant_weekly_report WHERE restaurant_id = p_restaurant_id AND report_week = week3_start;

-- Calculate trends IF w2_revenue > 0 THEN

revenue_growth := ROUND(((w1_revenue - w2_revenue) / w2_revenue) * 100, 2);

ELSE

revenue_growth := 0;

END IF;

IF w2_orders > 0 THEN

order_growth := ROUND(((w1_orders - w2_orders)::DECIMAL / w2_orders::DECIMAL) * 100, 2);

ELSE

order_growth := 0;

END IF;

-- Determine trend direction revenue_trend_val := CASE

WHEN revenue_growth > 5 THEN 'INCREASING' WHEN revenue_growth < -5 THEN 'DECREASING' ELSE 'STABLE'

END;

order_trend_val := CASE

WHEN order_growth > 5 THEN 'INCREASING' WHEN order_growth < -5 THEN 'DECREASING' ELSE 'STABLE'

END;

-- Generate alerts IF revenue_growth < -20 THEN

alerts := alerts
'{"type": "revenue_decline", "severity": "high", "message": "Revenue declined by more than 20% this week"}'::jsonb;

END IF;

IF order_growth < -15 THEN

alerts := alerts
'{"type": "order_decline", "severity": "medium", "message": "Order volume declined by more than 15% this week"}'::jsonb;

END IF;

-- Generate recommendations IF revenue_trend_val = 'DECREASING' THEN

recommendations := recommendations
'{"type": "marketing", "action": "Consider promotional campaigns or menu updates"}'::jsonb;

END IF;

IF order_trend_val = 'DECREASING' THEN

recommendations := recommendations
'{"type": "operations", "action": "Review menu pricing and delivery times"}'::jsonb;

END IF;

-- Insert trend analysis INSERT INTO restaurant_trend_analysis (

restaurant_id, week1_revenue, week2_revenue, week3_revenue, week1_orders, week2_orders, week3_orders, revenue_trend, order_trend, revenue_growth_rate, order_growth_rate, performance_alerts, recommendations

) VALUES (

p_restaurant_id, w1_revenue, w2_revenue, w3_revenue, w1_orders, w2_orders, w3_orders, revenue_trend_val, order_trend_val, revenue_growth, order_growth, alerts, recommendations

) ON CONFLICT (restaurant_id) DO UPDATE SET

week1_revenue = EXCLUDED.week1_revenue, week2_revenue = EXCLUDED.week2_revenue, week3_revenue = EXCLUDED.week3_revenue, week1_orders = EXCLUDED.week1_orders, week2_orders = EXCLUDED.week2_orders, week3_orders = EXCLUDED.week3_orders, revenue_trend = EXCLUDED.revenue_trend, order_trend = EXCLUDED.order_trend, revenue_growth_rate = EXCLUDED.revenue_growth_rate, order_growth_rate = EXCLUDED.order_growth_rate, performance_alerts = EXCLUDED.performance_alerts, recommendations = EXCLUDED.recommendations, generated_at = CURRENT_TIMESTAMP;

END; $$ LANGUAGE plpgsql;

Trigger Functions

Update Restaurant Reports Trigger Function

CREATE OR REPLACE FUNCTION update_restaurant_reports()

RETURNS TRIGGER AS $$

DECLARE

affected_restaurant_id INT; order_date_to_check DATE;

BEGIN

-- Determine which restaurant and date to update affected_restaurant_id := COALESCE(NEW.restaurant_id, OLD.restaurant_id); order_date_to_check := COALESCE(NEW.order_date::date, OLD.order_date::date);

-- Only update if the order is within the last 3 weeks IF order_date_to_check >= CURRENT_DATE - INTERVAL '21 days' THEN

-- Update reports for the affected week PERFORM generate_restaurant_weekly_report(affected_restaurant_id, order_date_to_check);

-- Update trend analysis PERFORM generate_trend_analysis(affected_restaurant_id);

-- Log the report update INSERT INTO audit_orders (order_id, operation, new_status, changed_by) VALUES (

COALESCE(NEW.order_id, OLD.order_id), 'REPORT_UPDATE', 'Restaurant report updated', 'system'

);

END IF;

RETURN COALESCE(NEW, OLD);

END; $$ LANGUAGE plpgsql;

Update Reports on Items Change Trigger Function

CREATE OR REPLACE FUNCTION update_reports_on_items_change()

RETURNS TRIGGER AS $$

DECLARE

affected_restaurant_id INT; order_date_to_check DATE;

BEGIN

-- Get restaurant and date from the order SELECT restaurant_id, order_date::date INTO affected_restaurant_id, order_date_to_check FROM orders WHERE order_id = COALESCE(NEW.order_id, OLD.order_id);

-- Only update if within the last 3 weeks IF order_date_to_check >= CURRENT_DATE - INTERVAL '21 days' THEN

PERFORM generate_restaurant_weekly_report(affected_restaurant_id, order_date_to_check); PERFORM generate_trend_analysis(affected_restaurant_id);

END IF;

RETURN COALESCE(NEW, OLD);

END; $$ LANGUAGE plpgsql;

Create Triggers

-- Trigger on orders table CREATE TRIGGER trg_update_restaurant_reports

AFTER INSERT OR UPDATE OR DELETE ON orders FOR EACH ROW

EXECUTE FUNCTION update_restaurant_reports();

-- Trigger on order_items table CREATE TRIGGER trg_update_reports_items

AFTER INSERT OR UPDATE OR DELETE ON order_items FOR EACH ROW

EXECUTE FUNCTION update_reports_on_items_change();

Report Views for Easy Access

Comprehensive 3-Week Restaurant Report View CREATE VIEW restaurant_3week_summary AS SELECT

r.name as restaurant_name, rwr.restaurant_id,

-- Current week (Week 1) MAX(CASE WHEN rwr.week_number = 1 THEN rwr.total_orders END) as current_week_orders, MAX(CASE WHEN rwr.week_number = 1 THEN rwr.gross_revenue END) as current_week_revenue, MAX(CASE WHEN rwr.week_number = 1 THEN rwr.completion_rate END) as current_week_completion_rate,

-- Previous week (Week 2) MAX(CASE WHEN rwr.week_number = 2 THEN rwr.total_orders END) as prev_week_orders, MAX(CASE WHEN rwr.week_number = 2 THEN rwr.gross_revenue END) as prev_week_revenue,

-- 3 weeks ago (Week 3) MAX(CASE WHEN rwr.week_number = 3 THEN rwr.total_orders END) as week3_orders, MAX(CASE WHEN rwr.week_number = 3 THEN rwr.gross_revenue END) as week3_revenue,

-- Totals SUM(rwr.total_orders) as total_orders_3weeks, SUM(rwr.gross_revenue) as total_revenue_3weeks, AVG(rwr.average_order_value) as avg_order_value_3weeks, AVG(rwr.completion_rate) as avg_completion_rate,

-- Operational insights MAX(CASE WHEN rwr.week_number = 1 THEN rwr.peak_hour END) as current_peak_hour, MAX(CASE WHEN rwr.week_number = 1 THEN rwr.busiest_day END) as current_busiest_day, AVG(rwr.avg_preparation_time_minutes) as avg_prep_time,

MAX(rwr.last_updated) as last_updated

FROM restaurant_weekly_report rwr

JOIN restaurant r ON rwr.restaurant_id = r.restaurant_id

WHERE rwr.report_week >= CURRENT_DATE - INTERVAL '21 days' GROUP BY r.name, rwr.restaurant_id;

Top Performing Restaurants View

CREATE VIEW top_restaurants_3weeks AS SELECT

r.name as restaurant_name, SUM(rwr.gross_revenue) as total_revenue, SUM(rwr.total_orders) as total_orders, AVG(rwr.completion_rate) as avg_completion_rate, AVG(rwr.average_order_value) as avg_order_value, rta.revenue_trend, rta.revenue_growth_rate

FROM restaurant_weekly_report rwr

JOIN restaurant r ON rwr.restaurant_id = r.restaurant_id LEFT JOIN restaurant_trend_analysis rta ON rwr.restaurant_id = rta.restaurant_id

WHERE rwr.report_week >= CURRENT_DATE - INTERVAL '21 days' GROUP BY r.name, rta.revenue_trend, rta.revenue_growth_rate ORDER BY total_revenue DESC;

Daily Reports Function

CREATE OR REPLACE FUNCTION generate_daily_breakdown_report(

p_restaurant_id INT, p_week_start DATE, p_week_end DATE

) RETURNS void

LANGUAGE plpgsql

AS $$ DECLARE

v_day DATE := p_week_start; v_daily_orders INTEGER := 0; v_daily_revenue NUMERIC(12,2) := 0; v_daily_items_sold INTEGER := 0; v_avg_order_value NUMERIC(12,2) := 0; v_hourly_orders JSONB := '{}'::jsonb;

BEGIN

IF p_week_end < p_week_start THEN

RAISE EXCEPTION 'p_week_end (%) must be >= p_week_start (%)', p_week_end, p_week_start;

END IF;

DELETE FROM restaurant_daily_breakdown WHERE restaurant_id = p_restaurant_id

AND report_date BETWEEN p_week_start AND p_week_end;

WHILE v_day <= p_week_end LOOP

-- Daily metrics SELECT

COUNT(*), COALESCE(SUM(total_amount), 0)::NUMERIC(12,2), COALESCE(AVG(total_amount), 0)::NUMERIC(12,2)

INTO v_daily_orders, v_daily_revenue, v_avg_order_value FROM orders WHERE restaurant_id = p_restaurant_id

AND order_date::date = v_day AND order_status = 'delivered';

-- Daily items sold SELECT COALESCE(SUM(oi.quantity), 0) INTO v_daily_items_sold FROM order_items oi

JOIN orders o ON oi.order_id = o.order_id

WHERE o.restaurant_id = p_restaurant_id

AND o.order_date::date = v_day AND o.order_status = 'delivered';

-- Hourly order breakdown (as JSONB) SELECT COALESCE(jsonb_object_agg(order_hour::text, order_count), '{}'::jsonb) INTO v_hourly_orders FROM (

SELECT

EXTRACT(hour FROM order_date) AS order_hour, COUNT(*) AS order_count

FROM orders WHERE restaurant_id = p_restaurant_id

AND order_date::date = v_day AND order_status = 'delivered'

GROUP BY 1

) AS hourly_counts;

-- Insert daily breakdown INSERT INTO restaurant_daily_breakdown (

restaurant_id, report_date, day_of_week, daily_orders, daily_revenue, daily_items_sold, avg_order_value, hourly_orders

) VALUES (

p_restaurant_id, v_day, EXTRACT(DOW FROM v_day), v_daily_orders, v_daily_revenue, v_daily_items_sold, v_avg_order_value, v_hourly_orders

);

-- Next day v_day := v_day + 1; -- date + integer yields date

END LOOP;

END; $$;

Constraint Addition

ALTER TABLE restaurant_trend_analysis

ADD CONSTRAINT uq_restaurant_id UNIQUE (restaurant_id);

Note: See TracWiki for help on using the wiki.