SQL · Student performance

Student Performance Risk Analysis

6,607 students × 20 features. Window-function rankings. 4 behavioral cohorts. Advising early-warning queue.

Analyst · PostgreSQL · cohort segmentation & reporting

Prior exam scores look like the safest way to flag struggling students — until you query the full 6,607-student table. Nearly a third of all at-risk exam outcomes (687 of 2,131 students scoring ≤ 65) entered with a prior score of 80 or higher (averaging 89.1) and slipped when attendance and weekly study hours fell. Meanwhile, monthly tutoring sessions sit flat (~1.47–1.51) across every risk band.

Full SQL analytical study on the public Student Performance Factors dataset (6,607 students × 20 academic, behavioral, and socioeconomic features). Built in PostgreSQL using statistical mode imputation, window functions (NTILE, PERCENT_RANK, partitioned peer averages), and operational advising views.

6,607Students audited across 20 features (235 nulls imputed, 1 score >100 capped)
+6.02 ptsExam score spread between Q4 and Q1 attendance (71.4% → 3.2% at-risk rate)
1,835“Drifting High-Potential” students (prior ≥ 80, current risk rate 37.1%)

Problem

Advising teams that filter on prior scores alone miss high-capability students who disengage mid-term, while tutoring sessions are spread evenly (~1.5/mo) regardless of risk.

Approach

Clean and encode all 20 columns in SQL (MODE() WITHIN GROUP, LEAST), rank all 19 predictors via NTILE(4) and CORR(), and segment students into 4 cohorts.

Insight

Current behavior dominates baseline advantage: Q4 vs. Q1 attendance moves exam scores by +6.02 pts and study hours by +4.56 pts, compared to +0.99 pts for family income and +0.08 pts for school type.

Impact

Replaces static GPA cutoffs with vw_advising_triage_queue: an actionable roster prioritizing “Silent Slip” and low-resource students who currently receive < 2 tutoring sessions.

Interactive SQL storyboard · 19 features & 4 cohorts

Use the tabs below to inspect the exact PostgreSQL query outputs across the 6,607-student dataset: the 19-feature driver leaderboard, the 4 behavioral cohorts, and the Attendance × Study Hours risk matrix.

Top Behavioral Driver +6.02 pts Attendance Q4 (70.21) vs Q1 (64.20)
Top Support Driver +1.89 pts Resources High (68.09) vs Low (66.20)
Silent Slip Cohort 687 Prior ≥ 80 who scored ≤ 65 (32.2% of all at-risk)
Tutoring Allocation 1.47 / mo Disengaged At-Risk vs 1.50 in High-Discipline
Domain:

Ranked by Top-to-Bottom Tier Exam Score Spread (NTILE(4) Q4 vs. Q1 for continuous variables; highest vs. lowest level for categoricals). At-risk is defined as exam_score <= 65 (bottom tertile, 32.3% overall).

1 · Data hygiene & mode imputation in SQL

Before running any aggregations, Section 2 of sql/student_performance_analysis.sql audits completeness and domain bounds across all 6,607 rows:

  • Range violation (1 row): One student record carried Exam_Score = 101 on a 100-point scale. Rather than dropping the student, LEAST(GREATEST(exam_score, 0), 100) caps the value cleanly at 100.
  • Missing categoricals (235 nulls across 3 columns): Parental_Education_Level (90 nulls, 1.36%), Teacher_Quality (78 nulls, 1.18%), and Distance_from_Home (67 nulls, 1.01%). A CTE computes each column’s statistical mode via PostgreSQL’s ordered-set aggregate MODE() WITHIN GROUP (ORDER BY col) and imputes missing values via COALESCE ('High School', 'Medium', and 'Near').
  • Ordinal & binary encoding: Every qualitative scale (Low / Medium / High, Negative / Neutral / Positive, Near / Moderate / Far) is mapped to 0 / 1 / 2 alongside the human-readable label so downstream views can compute composite indices and Pearson correlations directly in SQL.
CREATE OR REPLACE VIEW vw_student_factors_clean AS
WITH modal_defaults AS (
    SELECT
        MODE() WITHIN GROUP (ORDER BY teacher_quality)          AS mode_teacher_quality,
        MODE() WITHIN GROUP (ORDER BY parental_education_level) AS mode_parental_ed,
        MODE() WITHIN GROUP (ORDER BY distance_from_home)       AS mode_distance
    FROM raw_student_performance
)
SELECT
    ROW_NUMBER() OVER (
        ORDER BY r.exam_score DESC, r.attendance DESC, r.hours_studied DESC
    )                                                           AS student_id,
    r.hours_studied,
    r.attendance,
    r.previous_scores,
    r.sleep_hours,
    r.tutoring_sessions,
    r.physical_activity,
    LEAST(GREATEST(r.exam_score, 0), 100)                       AS exam_score,
    COALESCE(r.teacher_quality, m.mode_teacher_quality)         AS teacher_quality,
    COALESCE(r.parental_education_level, m.mode_parental_ed)    AS parental_education_level,
    COALESCE(r.distance_from_home, m.mode_distance)             AS distance_from_home
    -- + ordinal (0/1/2) and binary (0/1) encoded columns
FROM raw_student_performance AS r
CROSS JOIN modal_defaults AS m;

2 · Window functions & cohort segmentation

Instead of black-box clustering that advisors cannot audit, vw_student_analytical_profile segments students using transparent SQL rules and window functions that compare each student against their own school_type × family_income peer group:

Engineered SQL metrics

academic_momentum0.5*prev + 0.3*att + 0.2*hours (r = +0.474 with exam score)
productivity_ratiohours_studied / (sleep_hours + 1) (r = +0.378)
score_vs_peersexam_score - AVG(exam_score) OVER (PARTITION BY school_type, family_income)

4 behavioral cohorts

High-Discipline Anchorsatt >= 85 AND hours >= 20 (n = 1,342 · 0.7% at-risk)
Steady MiddleModerate attendance/hours (n = 2,775 · 30.6% at-risk)
Drifting High-Potentialprev >= 80 but att < 80 OR hours < 18 (n = 1,835 · 37.1% at-risk)
Disengaged At-Riskatt < 75 AND hours < 20 (n = 655 · 90.4% at-risk)

Interactive simulator · run the SQL triage logic

Test how vw_student_analytical_profile and vw_advising_triage_queue classify a student row and estimate at-risk probability from the dataset’s empirical cohort cells:

Advising Triage & Cohort Classifier

Matches the exact SQL CASE rules in vw_student_analytical_profile and vw_advising_triage_queue.

P1: Silent Slip · Drifting High-Potential (73.4% cell risk · Momentum 73.6)
Live evaluation of vw_student_analytical_profile & vw_advising_triage_queue

3 · The operational takeaway: reallocate tutoring to the “Silent Slip”

When you group the 6,607 students by Attendance Tier × Study Hours Tier (Section 7 of the SQL script), two facts jump off the page:

  • Prior scores do not protect against disengagement: Average Previous_Scores sits between 73.4 and 76.0 in every single cell of the 3×3 Attendance × Study matrix. Yet the at-risk rate (Exam_Score <= 65) swings from 97.1% (Attendance < 70%, Study < 15h) down to 0.2% (Attendance ≥ 85%, Study ≥ 25h).
  • 687 high-prior-score students failed the threshold: Out of 2,131 total at-risk students, 687 entered with Previous_Scores >= 80 (mean 89.1) but averaged 69.3% attendance and 16.1 study hours. Any advising filter that screens out students with strong prior grades misses nearly a third of all bad outcomes.
  • Tutoring is untargeted: Students with 3+ monthly tutoring sessions score +1.64 points higher and cut their at-risk rate nearly in half (40.3% → 22.4%), yet average tutoring across cohorts is completely flat (1.47/mo for Disengaged At-Risk and Drifting High-Potential vs. 1.50/mo for High-Discipline Anchors).
CREATE OR REPLACE VIEW vw_advising_triage_queue AS
SELECT
    student_id,
    cohort_segment,
    CASE
        WHEN previous_scores >= 80 AND attendance < 75 AND hours_studied < 18
            THEN 'P1: Silent Slip (High Prior Score, Acute Attendance/Study Drop)'
        WHEN attendance < 70 AND hours_studied < 15
            THEN 'P1: Critical Disengagement (97% Historical Risk Band)'
        WHEN access_to_resources = 'Low' AND internet_access = 'No'
            THEN 'P2: Resource & Connectivity Barrier'
        ELSE 'P3: Moderate Behavioral Drift'
    END AS triage_priority,
    previous_scores,
    attendance,
    hours_studied,
    tutoring_sessions,
    exam_score AS observed_exam_score,
    score_vs_income_school_peers
FROM vw_student_analytical_profile
WHERE attendance < 80
  AND hours_studied < 20
  AND tutoring_sessions < 2
ORDER BY
    CASE
        WHEN previous_scores >= 80 AND attendance < 75 AND hours_studied < 18 THEN 1
        WHEN attendance < 70 AND hours_studied < 15 THEN 2
        ELSE 3
    END,
    attendance ASC,
    hours_studied ASC;

4 · Conclusion: structuring classrooms to close the gap

A report is only useful if it tells a principal or academic dean what to change on Monday morning. Because a school cannot directly rewrite a student’s Family_Income or Parental_Education_Level, Section 9 of sql/student_performance_analysis.sql tests which classroom-level structures offset those baseline disadvantages inside the data:

1 · In-school study blocks for low-resource & long-commute students

Students with Access_to_Resources = 'Low' or Internet_Access = 'No' face a 64.2% at-risk rate (mean 64.44) when left with < 20 study hours and < 2 tutoring sessions. Embedding a structured school-day study block (reaching ≥ 20h/wk) plus ≥ 2 monthly tutoring sessions lifts their mean score to 68.24 (+3.80 pts) and cuts their at-risk rate to 19.3% — outperforming the overall school average.

2 · Peer-anchored seating & collaborative pods

Even in a classroom with Teacher_Quality = 'High', students in a Negative peer group carry a 38.2% at-risk rate (mean 66.81). Pairing high teacher quality with Positive peer influence drops the at-risk rate to 23.5% (mean 68.15). Structuring classrooms into mixed-cohort study pods — seating High-Discipline Anchors (92.3% attendance) alongside Drifting High-Potential students — turns peer influence into an instructional lever.

3 · Co-taught & tutoring-paired rosters for learning disabilities

Students with Learning_Disabilities = 'Yes' face a 50.9% at-risk rate (mean 65.49) when placed in standard classrooms with < 2 tutoring sessions. Intentional roster placement with a High quality teacher plus ≥ 2 monthly tutoring sessions raises their mean exam score to 67.64 (+2.15 pts) and reduces their at-risk rate to 29.3% (below the general-population risk rate of 32.3%).

4 · Attendance-triggered tutoring reallocation

Right now, monthly tutoring averages 1.50 sessions for High-Discipline Anchors (who already have a 0.7% risk rate) and 1.47 sessions for Drifting High-Potential and Disengaged At-Risk students. Reallocating 2+ monthly tutoring slots automatically whenever a student hits vw_advising_triage_queue shifts existing staff hours to the exact cohorts where an extra session cuts failure risk in half.

SQL intervention scorecard · Section 9 query output

Target Student Group Classroom Structure / Support Tier Students Mean Exam Score At-Risk Rate (≤65)
Low Resource or No Home Internet Baseline (<20h study & <2 tutoring/mo) 416 64.44 64.2%
Low Resource or No Home Internet In-School Study Block (20h+) + Tutoring (2+/mo) 445 68.24 (+3.80) 19.3% (−44.9 pp)
Learning Disabilities (Yes) Baseline (Standard Teacher & <2 tutoring/mo) 281 65.49 50.9%
Learning Disabilities (Yes) High Teacher Quality Roster + Tutoring (2+/mo) 99 67.64 (+2.15) 29.3% (−21.6 pp)
High Teacher Quality Classrooms Negative Peer Influence vs. Positive Peer Pods 403 vs. 765 66.81 → 68.15 38.2% → 23.5% (−14.7 pp)

Limitations & next steps in production

  • Cross-sectional grain: Each row is one student snapshot. In a live registrar warehouse, I would join weekly LMS login and attendance deltas (Week 4 vs. Week 1) so vw_advising_triage_queue triggers before midterms.
  • Self-reported study and sleep hours: Surveyed study hours can carry reporting bias, whereas registrar attendance and LMS submissions are system-logged.
  • Closed-loop tracking: Add an intervention_log table to measure whether reallocating tutoring vouchers to P1/P2 queue students actually recovers exam scores.
Next: Happiness and GDP↗ Next: Happiness and GDP↗ Next: Happiness and GDP↗