-- ===================================================== -- 指标趋势分析与拐点预警SQL -- Metric Trend Analysis and Turning Point Warning -- 数据库: PostgreSQL -- ===================================================== -- ===================================================== -- 1. 日度指标基础数据 -- ===================================================== WITH daily_metrics AS ( SELECT DATE(lr.event_time_utc::timestamp) AS metric_date, COUNT(DISTINCT lr.worker_name) AS worker_count, SUM(lr.duration_minutes) / 60.0 AS total_hours, SUM(lr.report_qty) AS total_output, CASE WHEN SUM(lr.duration_minutes) > 0 THEN SUM(lr.report_qty) / (SUM(lr.duration_minutes) / 60.0) ELSE 0 END AS hourly_efficiency FROM fact_labor_report lr GROUP BY DATE(lr.event_time_utc::timestamp) ), daily_quality AS ( SELECT DATE(qi.event_time_utc::timestamp) AS metric_date, SUM(qi.pass_qty) AS pass_qty, SUM(qi.fail_qty) AS fail_qty, CASE WHEN SUM(qi.pass_qty) + SUM(qi.fail_qty) > 0 THEN SUM(qi.fail_qty) * 100.0 / (SUM(qi.pass_qty) + SUM(qi.fail_qty)) ELSE 0 END AS defect_rate FROM fact_quality_inspection qi GROUP BY DATE(qi.event_time_utc::timestamp) ), daily_production AS ( SELECT DATE(wo.event_time_utc::timestamp) AS metric_date, SUM(wo.planned_qty) AS planned_qty, SUM(wo.completed_qty) AS completed_qty, CASE WHEN SUM(wo.planned_qty) > 0 THEN SUM(wo.completed_qty) * 100.0 / SUM(wo.planned_qty) ELSE 0 END AS completion_rate FROM fact_work_order wo GROUP BY DATE(wo.event_time_utc::timestamp) ), combined_daily AS ( SELECT COALESCE(dm.metric_date, dq.metric_date, dp.metric_date) AS metric_date, COALESCE(dm.worker_count, 0) AS worker_count, COALESCE(dm.total_hours, 0) AS total_hours, COALESCE(dm.total_output, 0) AS total_output, COALESCE(dm.hourly_efficiency, 0) AS hourly_efficiency, COALESCE(dq.defect_rate, 0) AS defect_rate, COALESCE(dp.completion_rate, 0) AS completion_rate FROM daily_metrics dm FULL OUTER JOIN daily_quality dq ON dm.metric_date = dq.metric_date FULL OUTER JOIN daily_production dp ON dm.metric_date = dp.metric_date WHERE COALESCE(dm.metric_date, dq.metric_date, dp.metric_date) IS NOT NULL ), numbered_data AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY metric_date) AS day_seq FROM combined_daily ), -- ===================================================== -- 2. 移动平均计算 (7日移动平均) -- ===================================================== moving_avg_step1 AS ( SELECT metric_date, day_seq, worker_count, total_output, hourly_efficiency, defect_rate, completion_rate, AVG(hourly_efficiency) OVER (ORDER BY metric_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7_efficiency, AVG(total_output) OVER (ORDER BY metric_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7_output, AVG(defect_rate) OVER (ORDER BY metric_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7_defect_rate, AVG(completion_rate) OVER (ORDER BY metric_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7_completion_rate, AVG(day_seq) OVER (ORDER BY metric_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS avg_x FROM numbered_data ), moving_avg AS ( SELECT *, LAG(ma7_efficiency, 1) OVER (ORDER BY metric_date) AS prev_ma7_efficiency, LAG(ma7_output, 1) OVER (ORDER BY metric_date) AS prev_ma7_output, LAG(ma7_defect_rate, 1) OVER (ORDER BY metric_date) AS prev_ma7_defect_rate FROM moving_avg_step1 ), -- ===================================================== -- 3. 简化的趋势斜率计算 -- ===================================================== slope_calc AS ( SELECT *, (ma7_efficiency - LAG(ma7_efficiency, 3) OVER (ORDER BY metric_date)) / 3.0 AS slope_efficiency, (ma7_output - LAG(ma7_output, 3) OVER (ORDER BY metric_date)) / 3.0 AS slope_output, (ma7_defect_rate - LAG(ma7_defect_rate, 3) OVER (ORDER BY metric_date)) / 3.0 AS slope_defect FROM moving_avg ), -- ===================================================== -- 4. 趋势判断与异常检测 -- ===================================================== trend_analysis AS ( SELECT metric_date, hourly_efficiency, total_output, defect_rate, completion_rate, ROUND(ma7_efficiency, 2) AS ma7_efficiency, ROUND(ma7_output, 2) AS ma7_output, ROUND(ma7_defect_rate, 2) AS ma7_defect_rate, ROUND(COALESCE(slope_efficiency, 0), 4) AS slope_efficiency, ROUND(COALESCE(slope_output, 0), 4) AS slope_output, ROUND(COALESCE(slope_defect, 0), 4) AS slope_defect, prev_ma7_efficiency, prev_ma7_output, prev_ma7_defect_rate, CASE WHEN COALESCE(slope_efficiency, 0) > 0.3 THEN 'RISING' WHEN COALESCE(slope_efficiency, 0) < -0.3 THEN 'FALLING' ELSE 'STABLE' END AS efficiency_trend, CASE WHEN COALESCE(slope_output, 0) > 3 THEN 'RISING' WHEN COALESCE(slope_output, 0) < -3 THEN 'FALLING' ELSE 'STABLE' END AS output_trend, CASE WHEN COALESCE(slope_defect, 0) > 0.3 THEN 'RISING' WHEN COALESCE(slope_defect, 0) < -0.3 THEN 'FALLING' ELSE 'STABLE' END AS defect_trend, CASE WHEN ma7_efficiency > 0 AND ABS(hourly_efficiency - ma7_efficiency) > ma7_efficiency * 0.3 THEN 'ANOMALY' ELSE 'NORMAL' END AS efficiency_status, CASE WHEN ma7_output > 0 AND ABS(total_output - ma7_output) > ma7_output * 0.3 THEN 'ANOMALY' ELSE 'NORMAL' END AS output_status, CASE WHEN defect_rate > ma7_defect_rate * 1.5 AND defect_rate > 5 THEN 'ANOMALY' ELSE 'NORMAL' END AS defect_status FROM slope_calc ) -- ===================================================== -- 输出:日度趋势分析明细 -- ===================================================== SELECT metric_date, ROUND(hourly_efficiency, 2) AS hourly_output, ma7_efficiency AS efficiency_ma7, slope_efficiency, efficiency_trend, efficiency_status, CASE WHEN prev_ma7_efficiency IS NOT NULL AND ma7_efficiency > prev_ma7_efficiency AND slope_efficiency < 0 THEN 'TURNING_POINT' WHEN prev_ma7_efficiency IS NOT NULL AND ma7_efficiency < prev_ma7_efficiency AND slope_efficiency > 0 THEN 'TURNING_POINT' ELSE 'NONE' END AS efficiency_turning_point, ROUND(total_output, 0) AS daily_output, ma7_output AS output_ma7, slope_output, output_trend, output_status, CASE WHEN prev_ma7_output IS NOT NULL AND ma7_output > prev_ma7_output AND slope_output < 0 THEN 'TURNING_POINT' WHEN prev_ma7_output IS NOT NULL AND ma7_output < prev_ma7_output AND slope_output > 0 THEN 'TURNING_POINT' ELSE 'NONE' END AS output_turning_point, ROUND(defect_rate, 2) AS defect_rate, ma7_defect_rate AS defect_rate_ma7, slope_defect, defect_trend, defect_status, CASE WHEN prev_ma7_defect_rate IS NOT NULL AND ma7_defect_rate > prev_ma7_defect_rate AND slope_defect < 0 THEN 'TURNING_POINT' WHEN prev_ma7_defect_rate IS NOT NULL AND ma7_defect_rate < prev_ma7_defect_rate AND slope_defect > 0 THEN 'TURNING_POINT' ELSE 'NONE' END AS defect_turning_point FROM trend_analysis ORDER BY metric_date DESC; -- ===================================================== -- 补充查询1:周度趋势汇总 -- ===================================================== WITH weekly_metrics AS ( SELECT DATE_TRUNC('week', lr.event_time_utc::timestamp)::date AS week_start, COUNT(DISTINCT lr.worker_name) AS worker_count, SUM(lr.duration_minutes) / 60.0 AS total_hours, SUM(lr.report_qty) AS total_output, CASE WHEN SUM(lr.duration_minutes) > 0 THEN SUM(lr.report_qty) / (SUM(lr.duration_minutes) / 60.0) ELSE 0 END AS hourly_efficiency FROM fact_labor_report lr GROUP BY DATE_TRUNC('week', lr.event_time_utc::timestamp) ), weekly_quality AS ( SELECT DATE_TRUNC('week', qi.event_time_utc::timestamp)::date AS week_start, SUM(qi.fail_qty) * 100.0 / NULLIF(SUM(qi.pass_qty) + SUM(qi.fail_qty), 0) AS defect_rate FROM fact_quality_inspection qi GROUP BY DATE_TRUNC('week', qi.event_time_utc::timestamp) ), weekly_combined AS ( SELECT wm.week_start, wm.worker_count, wm.total_hours, wm.total_output, wm.hourly_efficiency, COALESCE(wq.defect_rate, 0) AS defect_rate FROM weekly_metrics wm LEFT JOIN weekly_quality wq ON wm.week_start = wq.week_start ), weekly_with_lag AS ( SELECT *, LAG(hourly_efficiency, 1) OVER (ORDER BY week_start) AS prev_efficiency, LAG(total_output, 1) OVER (ORDER BY week_start) AS prev_output, LAG(defect_rate, 1) OVER (ORDER BY week_start) AS prev_defect_rate FROM weekly_combined ) SELECT week_start, worker_count, ROUND(total_hours, 1) AS total_hours, ROUND(total_output, 0) AS total_output, ROUND(hourly_efficiency, 2) AS hourly_output, ROUND(defect_rate, 2) AS defect_rate, CASE WHEN prev_efficiency IS NULL THEN 'NONE' WHEN hourly_efficiency > prev_efficiency * 1.1 THEN 'RISING' WHEN hourly_efficiency < prev_efficiency * 0.9 THEN 'FALLING' ELSE 'STABLE' END AS efficiency_trend, CASE WHEN prev_output IS NULL THEN 'NONE' WHEN total_output > prev_output * 1.1 THEN 'RISING' WHEN total_output < prev_output * 0.9 THEN 'FALLING' ELSE 'STABLE' END AS output_trend, CASE WHEN prev_defect_rate IS NULL THEN 'NONE' WHEN defect_rate > prev_defect_rate * 1.2 THEN 'RISING' WHEN defect_rate < prev_defect_rate * 0.8 THEN 'FALLING' ELSE 'STABLE' END AS defect_trend, ROUND((hourly_efficiency - COALESCE(prev_efficiency, hourly_efficiency)) / NULLIF(prev_efficiency, 0) * 100, 1) AS efficiency_wow_pct FROM weekly_with_lag ORDER BY week_start DESC; -- ===================================================== -- 补充查询2:指标趋势汇总报告 -- ===================================================== WITH recent_data AS ( SELECT DATE(lr.event_time_utc::timestamp) AS metric_date, SUM(lr.report_qty) / NULLIF(SUM(lr.duration_minutes) / 60.0, 0) AS hourly_efficiency, SUM(lr.report_qty) AS total_output FROM fact_labor_report lr WHERE lr.event_time_utc::timestamp >= CURRENT_DATE - INTERVAL '14 days' GROUP BY DATE(lr.event_time_utc::timestamp) ), recent_quality AS ( SELECT DATE(qi.event_time_utc::timestamp) AS metric_date, SUM(qi.fail_qty) * 100.0 / NULLIF(SUM(qi.pass_qty) + SUM(qi.fail_qty), 0) AS defect_rate FROM fact_quality_inspection qi WHERE qi.event_time_utc::timestamp >= CURRENT_DATE - INTERVAL '14 days' GROUP BY DATE(qi.event_time_utc::timestamp) ), period_stats AS ( SELECT AVG(CASE WHEN rd.metric_date >= CURRENT_DATE - INTERVAL '7 days' THEN rd.hourly_efficiency END) AS avg_eff_7d, AVG(CASE WHEN rd.metric_date >= CURRENT_DATE - INTERVAL '7 days' THEN rd.total_output END) AS avg_output_7d, AVG(CASE WHEN rd.metric_date < CURRENT_DATE - INTERVAL '7 days' THEN rd.hourly_efficiency END) AS avg_eff_prev7d, AVG(CASE WHEN rd.metric_date < CURRENT_DATE - INTERVAL '7 days' THEN rd.total_output END) AS avg_output_prev7d FROM recent_data rd ), quality_stats AS ( SELECT AVG(CASE WHEN rq.metric_date >= CURRENT_DATE - INTERVAL '7 days' THEN rq.defect_rate END) AS avg_defect_7d, AVG(CASE WHEN rq.metric_date < CURRENT_DATE - INTERVAL '7 days' THEN rq.defect_rate END) AS avg_defect_prev7d FROM recent_quality rq ) SELECT 'efficiency_per_hour' AS metric_name, ROUND(ps.avg_eff_7d, 2) AS last_7d_avg, ROUND(ps.avg_eff_prev7d, 2) AS prev_7d_avg, ROUND((ps.avg_eff_7d - ps.avg_eff_prev7d) / NULLIF(ps.avg_eff_prev7d, 0) * 100, 1) AS change_rate_pct, CASE WHEN ps.avg_eff_7d > ps.avg_eff_prev7d * 1.05 THEN 'RISING' WHEN ps.avg_eff_7d < ps.avg_eff_prev7d * 0.95 THEN 'FALLING' ELSE 'STABLE' END AS trend, CASE WHEN ABS(ps.avg_eff_7d - ps.avg_eff_prev7d) / NULLIF(ps.avg_eff_prev7d, 0) > 0.2 THEN 'ANOMALY' ELSE 'NORMAL' END AS warning FROM period_stats ps UNION ALL SELECT 'daily_output', ROUND(ps.avg_output_7d, 0), ROUND(ps.avg_output_prev7d, 0), ROUND((ps.avg_output_7d - ps.avg_output_prev7d) / NULLIF(ps.avg_output_prev7d, 0) * 100, 1), CASE WHEN ps.avg_output_7d > ps.avg_output_prev7d * 1.05 THEN 'RISING' WHEN ps.avg_output_7d < ps.avg_output_prev7d * 0.95 THEN 'FALLING' ELSE 'STABLE' END, CASE WHEN ABS(ps.avg_output_7d - ps.avg_output_prev7d) / NULLIF(ps.avg_output_prev7d, 0) > 0.2 THEN 'ANOMALY' ELSE 'NORMAL' END FROM period_stats ps UNION ALL SELECT 'defect_rate_pct', ROUND(qs.avg_defect_7d, 2), ROUND(qs.avg_defect_prev7d, 2), ROUND((qs.avg_defect_7d - qs.avg_defect_prev7d) / NULLIF(qs.avg_defect_prev7d, 0) * 100, 1), CASE WHEN qs.avg_defect_7d > qs.avg_defect_prev7d * 1.1 THEN 'RISING' WHEN qs.avg_defect_7d < qs.avg_defect_prev7d * 0.9 THEN 'FALLING' ELSE 'STABLE' END, CASE WHEN qs.avg_defect_7d > 8 THEN 'THRESHOLD_EXCEEDED' WHEN qs.avg_defect_7d > qs.avg_defect_prev7d * 1.3 THEN 'ANOMALY_RISING' ELSE 'NORMAL' END FROM quality_stats qs; -- ===================================================== -- 补充查询3:拐点预警汇总 -- ===================================================== WITH daily_eff AS ( SELECT DATE(lr.event_time_utc::timestamp) AS metric_date, SUM(lr.report_qty) / NULLIF(SUM(lr.duration_minutes) / 60.0, 0) AS hourly_efficiency FROM fact_labor_report lr GROUP BY DATE(lr.event_time_utc::timestamp) ), with_ma_step1 AS ( SELECT metric_date, hourly_efficiency, AVG(hourly_efficiency) OVER (ORDER BY metric_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7 FROM daily_eff ), with_ma AS ( SELECT metric_date, hourly_efficiency, ma7, LAG(ma7, 1) OVER (ORDER BY metric_date) AS prev_ma7, LAG(ma7, 2) OVER (ORDER BY metric_date) AS prev2_ma7 FROM with_ma_step1 ), turning_points AS ( SELECT metric_date, hourly_efficiency, ma7, prev_ma7, prev2_ma7, CASE WHEN prev2_ma7 IS NOT NULL AND prev_ma7 < prev2_ma7 AND ma7 > prev_ma7 THEN 'UPWARD' WHEN prev2_ma7 IS NOT NULL AND prev_ma7 > prev2_ma7 AND ma7 < prev_ma7 THEN 'DOWNWARD' ELSE NULL END AS turning_type FROM with_ma ) SELECT metric_date, ROUND(hourly_efficiency, 2) AS daily_efficiency, ROUND(ma7, 2) AS ma7_line, turning_type, CASE WHEN turning_type = 'UPWARD' THEN 'MAINTAIN_CURRENT_MEASURES' WHEN turning_type = 'DOWNWARD' THEN 'INVESTIGATE_AND_IMPROVE' ELSE 'NONE' END AS recommendation FROM turning_points WHERE turning_type IS NOT NULL ORDER BY metric_date DESC LIMIT 10;