02_create_views.sql
-- Materialized Views for Fast Dashboard Queries
-- Run after 01_create_tables.sql
-- ============================================================================
-- TOP PATHS VIEW (leaderboard data)
-- ============================================================================
CREATE OR REPLACE VIEW `causal_roi.v_top_paths_7d` AS
WITH recent_paths AS (
SELECT
pm.path_id,
AVG(pm.velocity_ms) AS avg_velocity_ms,
AVG(pm.p_causal) AS avg_p_causal,
AVG(pm.pcr) AS avg_pcr,
AVG(pm.roi_delta) AS avg_roi_delta,
SUM(pm.n_actions) AS total_actions,
SUM(pm.n_outcomes) AS total_outcomes,
STDDEV(pm.roi_delta) AS roi_stddev
FROM `causal_roi.path_metrics` pm
WHERE pm.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY pm.path_id
)
SELECT
rp.*,
-- Rank by confidence-weighted ROI
ROW_NUMBER() OVER (ORDER BY rp.avg_roi_delta * rp.avg_p_causal DESC) AS rank,
-- Stability score (lower variance = more stable)
1.0 / (1.0 + rp.roi_stddev) AS stability_score
FROM recent_paths rp
WHERE rp.total_actions >= 10 -- min sample size
ORDER BY rank
LIMIT 100;
-- ============================================================================
-- EDGE DETAIL VIEW (for graph visualization)
-- ============================================================================
CREATE OR REPLACE VIEW `causal_roi.v_edge_details` AS
SELECT
e.edge_id,
e.src_node_id,
e.dst_node_id,
e.edge_type,
e.latest_delta_roi,
e.latest_latency_ms,
e.decay_weight,
e.n_observations,
e.last_updated,
-- Join node labels
src.label AS src_label,
src.node_type AS src_type,
dst.label AS dst_label,
dst.node_type AS dst_type,
-- Latest 7d metrics
em_recent.avg_delta_roi_7d,
em_recent.total_spend_7d,
em_recent.total_obs_7d
FROM `causal_roi.edges` e
LEFT JOIN `causal_roi.nodes` src ON e.src_node_id = src.node_id
LEFT JOIN `causal_roi.nodes` dst ON e.dst_node_id = dst.node_id
LEFT JOIN (
SELECT
edge_id,
AVG(delta_roi) AS avg_delta_roi_7d,
SUM(spend) AS total_spend_7d,
SUM(n_obs) AS total_obs_7d
FROM `causal_roi.edge_metrics`
WHERE date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY edge_id
) em_recent ON e.edge_id = em_recent.edge_id;
-- ============================================================================
-- PATH DETAIL VIEW (single path deep dive)
-- ============================================================================
CREATE OR REPLACE VIEW `causal_roi.v_path_detail` AS
WITH path_edges AS (
SELECT
em.path_id,
em.edge_id,
em.date,
em.delta_roi,
em.latency_ms,
em.spend,
em.n_obs
FROM `causal_roi.edge_metrics` em
WHERE em.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
),
path_timeseries AS (
SELECT
path_id,
date,
SUM(delta_roi * spend) / NULLIF(SUM(spend), 0) AS weighted_roi,
SUM(spend) AS daily_spend,
AVG(latency_ms) AS avg_latency
FROM path_edges
GROUP BY path_id, date
)
SELECT
pts.path_id,
pts.date,
pts.weighted_roi,
pts.daily_spend,
pts.avg_latency,
-- Running 7d average
AVG(pts.weighted_roi) OVER (
PARTITION BY pts.path_id
ORDER BY pts.date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS roi_7d_ma
FROM path_timeseries pts;
-- ============================================================================
-- DIAGNOSTICS VIEW (system health)
-- ============================================================================
CREATE OR REPLACE VIEW `causal_roi.v_diagnostics_daily` AS
WITH daily_stats AS (
SELECT
DATE(created_at) AS date,
'events_forecast' AS table_name,
COUNT(*) AS row_count,
MAX(created_at) AS last_insert
FROM `causal_roi.events_forecast`
WHERE DATE(created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY date
UNION ALL
SELECT
DATE(created_at),
'events_action',
COUNT(*),
MAX(created_at)
FROM `causal_roi.events_action`
WHERE DATE(created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY date
UNION ALL
SELECT
DATE(created_at),
'events_outcome',
COUNT(*),
MAX(created_at)
FROM `causal_roi.events_outcome`
WHERE DATE(created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY date
),
attribution_coverage AS (
SELECT
DATE(al.created_at) AS date,
al.method,
COUNT(DISTINCT al.path_id) AS paths_covered,
AVG(al.weight) AS avg_weight
FROM `causal_roi.attribution_links` al
WHERE DATE(al.created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY date, al.method
),
control_quality AS (
SELECT
DATE(cc.created_at) AS date,
cc.method AS control_method,
COUNT(*) AS n_controls,
AVG(cc.quality_score) AS avg_quality
FROM `causal_roi.control_cohorts` cc
WHERE DATE(cc.created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY date, cc.method
)
SELECT
ds.date,
-- Ingest health
SUM(CASE WHEN ds.table_name = 'events_forecast' THEN ds.row_count ELSE 0 END) AS forecasts_logged,
SUM(CASE WHEN ds.table_name = 'events_action' THEN ds.row_count ELSE 0 END) AS actions_logged,
SUM(CASE WHEN ds.table_name = 'events_outcome' THEN ds.row_count ELSE 0 END) AS outcomes_logged,
MAX(ds.last_insert) AS last_data_insert,
-- Attribution coverage
ac.paths_covered AS attributed_paths,
ac.avg_weight AS avg_attribution_weight,
-- Control quality
cq.n_controls,
cq.avg_quality AS control_quality_score
FROM daily_stats ds
LEFT JOIN attribution_coverage ac ON ds.date = ac.date
LEFT JOIN control_quality cq ON ds.date = cq.date
GROUP BY ds.date, ac.paths_covered, ac.avg_weight, cq.n_controls, cq.avg_quality
ORDER BY ds.date DESC;
-- ============================================================================
-- SYSTEM-WIDE SUMMARY (top bar metrics)
-- ============================================================================
CREATE OR REPLACE VIEW `causal_roi.v_system_summary` AS
WITH today_metrics AS (
SELECT
SUM(pm.roi_delta * pm.n_actions) / NULLIF(SUM(pm.n_actions), 0) AS net_delta_roi,
AVG(pm.velocity_ms) AS mean_velocity_ms,
SUM(pm.p_causal * CASE WHEN pm.roi_delta > 0 THEN 1 ELSE 0 END) /
NULLIF(SUM(pm.p_causal), 0) AS system_pcr
FROM `causal_roi.path_metrics` pm
WHERE pm.date = CURRENT_DATE()
)
SELECT
CURRENT_DATE() AS snapshot_date,
tm.net_delta_roi,
tm.mean_velocity_ms,
tm.system_pcr,
-- Change from yesterday
tm.net_delta_roi - COALESCE(yesterday.net_delta_roi, 0) AS delta_roi_change,
tm.mean_velocity_ms - COALESCE(yesterday.mean_velocity_ms, 0) AS velocity_change,
tm.system_pcr - COALESCE(yesterday.system_pcr, 0) AS pcr_change
FROM today_metrics tm
LEFT JOIN (
SELECT
SUM(pm.roi_delta * pm.n_actions) / NULLIF(SUM(pm.n_actions), 0) AS net_delta_roi,
AVG(pm.velocity_ms) AS mean_velocity_ms,
SUM(pm.p_causal * CASE WHEN pm.roi_delta > 0 THEN 1 ELSE 0 END) /
NULLIF(SUM(pm.p_causal), 0) AS system_pcr
FROM `causal_roi.path_metrics` pm
WHERE pm.date = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
) yesterday ON TRUE;
-- ============================================================================
-- EDGE HISTORY (for sparklines)
-- ============================================================================
CREATE OR REPLACE VIEW `causal_roi.v_edge_history_7d` AS
SELECT
em.edge_id,
em.date,
em.delta_roi,
em.n_obs,
em.spend,
-- Trend detection
AVG(em.delta_roi) OVER (
PARTITION BY em.edge_id
ORDER BY em.date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS roi_3d_ma,
-- Volatility
STDDEV(em.delta_roi) OVER (
PARTITION BY em.edge_id
ORDER BY em.date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS roi_7d_stddev
FROM `causal_roi.edge_metrics` em
WHERE em.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
ORDER BY em.edge_id, em.date;