letudiant_admin / scripts /recompute_scores.sql
Luli Maruyama
Deploy app to Hugging Face Space (no binaries)
9e42d3b
Raw History Blame Contribute Delete
9.74 kB
PRAGMA foreign_keys = ON;
BEGIN TRANSACTION;
DELETE FROM kpi_daily;
DELETE FROM monetization;
DELETE FROM lead_scores;
DELETE FROM derived_features;
INSERT INTO derived_features (
fair_id,
student_id,
snapshot_date,
checked_in,
repeat_visitor,
fields_interest_count,
programme_interest_present,
bac_track_present,
region_present,
phone_present,
consent_partner,
consent_call,
ori_completed,
ori_score,
bookmarks_count,
exit_clarity_score,
stands_tapped_count,
unique_stand_categories,
conference_scans_count,
exhibitor_scans_count,
passport_completed,
post_fair_email_clicks_count,
site_pageviews_7d,
followup_cta_to_exhibitor,
profile_rich,
created_at,
updated_at
)
WITH event_rollup AS (
SELECT
e.fair_id,
e.student_id,
MAX(CASE WHEN e.event_type = 'check_in' THEN 1 ELSE 0 END) AS checked_in,
SUM(CASE WHEN e.event_type = 'brochure_request' THEN 1 ELSE 0 END) AS bookmarks_count,
AVG(CASE WHEN e.event_type = 'exit_survey' THEN CAST(json_extract(e.payload_json, '$.clarity_score') AS REAL) END) AS exit_clarity_score,
SUM(CASE WHEN e.event_type = 'stand_tap' THEN 1 ELSE 0 END) AS stands_tapped_count,
COUNT(DISTINCT CASE WHEN e.event_type = 'stand_tap' THEN st.stand_category END) AS unique_stand_categories,
SUM(CASE WHEN e.event_type = 'conference_scan' THEN 1 ELSE 0 END) AS conference_scans_count,
SUM(CASE WHEN e.event_type = 'exhibitor_scan' THEN 1 ELSE 0 END) AS exhibitor_scans_count,
MAX(
CASE
WHEN e.event_type = 'passport_progress'
AND (
COALESCE(CAST(json_extract(e.payload_json, '$.completed') AS INTEGER), 0) = 1
OR COALESCE(CAST(json_extract(e.payload_json, '$.progress') AS INTEGER), 0) >= 100
)
THEN 1
ELSE 0
END
) AS passport_completed,
SUM(CASE WHEN e.event_type = 'post_fair_email_click' THEN 1 ELSE 0 END) AS post_fair_email_clicks_count,
SUM(
CASE
WHEN e.event_type = 'site_page_view'
AND (julianday(DATE(e.event_time)) - julianday(f.ends_on)) BETWEEN 0 AND 7
THEN 1
ELSE 0
END
) AS site_pageviews_7d,
MAX(CASE WHEN e.event_type = 'followup_cta_to_exhibitor' THEN 1 ELSE 0 END) AS followup_cta_to_exhibitor
FROM events e
JOIN fairs f ON f.id = e.fair_id
LEFT JOIN stands st ON st.id = e.stand_id
GROUP BY e.fair_id, e.student_id
)
SELECT
s.fair_id,
s.id AS student_id,
DATE('now') AS snapshot_date,
COALESCE(er.checked_in, 0) AS checked_in,
COALESCE(s.repeat_visitor, 0) AS repeat_visitor,
COALESCE(sp.fields_interest_count, 0) AS fields_interest_count,
CASE WHEN sp.programme_of_interest IS NOT NULL AND TRIM(sp.programme_of_interest) <> '' THEN 1 ELSE 0 END AS programme_interest_present,
CASE WHEN sp.bac_track_type IS NOT NULL AND TRIM(sp.bac_track_type) <> '' THEN 1 ELSE 0 END AS bac_track_present,
CASE WHEN sp.postal_region IS NOT NULL AND TRIM(sp.postal_region) <> '' THEN 1 ELSE 0 END AS region_present,
CASE WHEN sp.phone IS NOT NULL AND TRIM(sp.phone) <> '' THEN 1 ELSE 0 END AS phone_present,
COALESCE(sc.consent_partners, 0) AS consent_partner,
COALESCE(sc.consent_call, 0) AS consent_call,
COALESCE(s.used_ori, 0) AS ori_completed,
pfs.ori_test_score AS ori_score,
COALESCE(er.bookmarks_count, 0) AS bookmarks_count,
er.exit_clarity_score,
COALESCE(er.stands_tapped_count, 0) AS stands_tapped_count,
COALESCE(er.unique_stand_categories, 0) AS unique_stand_categories,
COALESCE(er.conference_scans_count, 0) AS conference_scans_count,
COALESCE(er.exhibitor_scans_count, 0) AS exhibitor_scans_count,
COALESCE(er.passport_completed, 0) AS passport_completed,
COALESCE(er.post_fair_email_clicks_count, 0) AS post_fair_email_clicks_count,
COALESCE(er.site_pageviews_7d, 0) AS site_pageviews_7d,
COALESCE(er.followup_cta_to_exhibitor, 0) AS followup_cta_to_exhibitor,
COALESCE(sp.profile_rich, 0) AS profile_rich,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
FROM students s
LEFT JOIN student_profiles sp ON sp.student_id = s.id
LEFT JOIN student_consents sc ON sc.student_id = s.id
LEFT JOIN pre_fair_signals pfs ON pfs.student_id = s.id
LEFT JOIN event_rollup er ON er.student_id = s.id AND er.fair_id = s.fair_id;
INSERT INTO lead_scores (
fair_id,
student_id,
intent_score,
engagement_score,
monetisability_score,
richness_score,
total_score,
prequalified,
scoring_version,
created_at,
updated_at
)
WITH calc AS (
SELECT
df.fair_id,
df.student_id,
(
20.0 * MIN(df.fields_interest_count, 3) / 3.0
+ 15.0 * df.programme_interest_present
+ 10.0 * df.repeat_visitor
+ 15.0 * MIN(df.bookmarks_count, 6) / 6.0
+ 20.0 * df.ori_completed * (CASE WHEN df.ori_score IS NOT NULL THEN df.ori_score / 100.0 ELSE 1.0 END)
+ 20.0 * (CASE WHEN df.exit_clarity_score IS NOT NULL THEN df.exit_clarity_score / 5.0 ELSE 0.0 END)
) AS intent_score,
(
10.0 * df.checked_in
+ 25.0 * MIN(df.stands_tapped_count, 8) / 8.0
+ 10.0 * MIN(df.unique_stand_categories, 4) / 4.0
+ 10.0 * MIN(df.conference_scans_count, 2) / 2.0
+ 20.0 * MIN(df.exhibitor_scans_count, 2) / 2.0
+ 10.0 * df.passport_completed
+ 10.0 * MIN(df.post_fair_email_clicks_count, 3) / 3.0
+ 5.0 * MIN(df.site_pageviews_7d, 6) / 6.0
) AS engagement_score,
(
45.0 * df.consent_partner
+ 15.0 * df.phone_present
+ 10.0 * df.consent_call
+ 10.0 * df.profile_rich
+ 10.0 * CASE WHEN df.exhibitor_scans_count > 0 THEN 1 ELSE 0 END
+ 10.0 * df.followup_cta_to_exhibitor
) AS monetisability_score,
(
25.0 * MIN(df.fields_interest_count, 3) / 3.0
+ 20.0 * df.programme_interest_present
+ 15.0 * df.bac_track_present
+ 15.0 * df.region_present
+ 25.0 * df.phone_present
) AS richness_score,
CASE
WHEN df.exhibitor_scans_count > 0 OR (df.consent_call = 1 AND df.followup_cta_to_exhibitor = 1) THEN 1
ELSE 0
END AS prequalified
FROM derived_features df
)
SELECT
c.fair_id,
c.student_id,
ROUND(c.intent_score, 4) AS intent_score,
ROUND(c.engagement_score, 4) AS engagement_score,
ROUND(c.monetisability_score, 4) AS monetisability_score,
ROUND(c.richness_score, 4) AS richness_score,
ROUND(0.40 * c.intent_score + 0.40 * c.engagement_score + 0.20 * c.monetisability_score, 4) AS total_score,
c.prequalified,
'v1',
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
FROM calc c;
INSERT INTO monetization (
fair_id,
student_id,
tier_eur,
resell_factor,
monetisable_value_eur,
created_at,
updated_at
)
SELECT
df.fair_id,
df.student_id,
CASE
WHEN df.consent_partner = 0 THEN 0.0
WHEN ls.prequalified = 1 THEN 23.0
WHEN df.profile_rich = 1 THEN 22.5
WHEN df.phone_present = 1 THEN 15.0
ELSE 3.0
END AS tier_eur,
CASE
WHEN df.unique_stand_categories <= 1 THEN 1
WHEN df.unique_stand_categories = 2 THEN 2
ELSE 3
END AS resell_factor,
(
CASE
WHEN df.consent_partner = 0 THEN 0.0
WHEN ls.prequalified = 1 THEN 23.0
WHEN df.profile_rich = 1 THEN 22.5
WHEN df.phone_present = 1 THEN 15.0
ELSE 3.0
END
* CASE
WHEN df.unique_stand_categories <= 1 THEN 1
WHEN df.unique_stand_categories = 2 THEN 2
ELSE 3
END
) AS monetisable_value_eur,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
FROM derived_features df
JOIN lead_scores ls
ON ls.fair_id = df.fair_id
AND ls.student_id = df.student_id;
INSERT INTO kpi_daily (
fair_id,
kpi_date,
total_students,
checked_in_students,
stand_taps,
conference_scans,
exhibitor_scans,
post_fair_email_clicks,
partner_optin_rate,
call_optin_rate,
total_monetisable_value_eur,
created_at,
updated_at
)
WITH day_events AS (
SELECT
e.fair_id,
DATE(e.event_time) AS kpi_date,
COUNT(DISTINCT CASE WHEN e.event_type = 'check_in' THEN e.student_id END) AS checked_in_students,
SUM(CASE WHEN e.event_type = 'stand_tap' THEN 1 ELSE 0 END) AS stand_taps,
SUM(CASE WHEN e.event_type = 'conference_scan' THEN 1 ELSE 0 END) AS conference_scans,
SUM(CASE WHEN e.event_type = 'exhibitor_scan' THEN 1 ELSE 0 END) AS exhibitor_scans,
SUM(CASE WHEN e.event_type = 'post_fair_email_click' THEN 1 ELSE 0 END) AS post_fair_email_clicks
FROM events e
GROUP BY e.fair_id, DATE(e.event_time)
),
optins AS (
SELECT
s.fair_id,
AVG(CAST(sc.consent_partners AS REAL)) AS partner_optin_rate,
AVG(CAST(sc.consent_call AS REAL)) AS call_optin_rate
FROM students s
LEFT JOIN student_consents sc ON sc.student_id = s.id
GROUP BY s.fair_id
),
day_values AS (
WITH active_students AS (
SELECT DISTINCT
e.fair_id,
DATE(e.event_time) AS kpi_date,
e.student_id
FROM events e
)
SELECT
a.fair_id,
a.kpi_date,
SUM(m.monetisable_value_eur) AS total_monetisable_value_eur
FROM active_students a
JOIN monetization m
ON m.student_id = a.student_id
AND m.fair_id = a.fair_id
GROUP BY a.fair_id, a.kpi_date
)
SELECT
de.fair_id,
de.kpi_date,
(SELECT COUNT(*) FROM students s WHERE s.fair_id = de.fair_id) AS total_students,
de.checked_in_students,
de.stand_taps,
de.conference_scans,
de.exhibitor_scans,
de.post_fair_email_clicks,
ROUND(COALESCE(o.partner_optin_rate, 0), 4) AS partner_optin_rate,
ROUND(COALESCE(o.call_optin_rate, 0), 4) AS call_optin_rate,
ROUND(COALESCE(dv.total_monetisable_value_eur, 0), 2) AS total_monetisable_value_eur,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
FROM day_events de
LEFT JOIN optins o
ON o.fair_id = de.fair_id
LEFT JOIN day_values dv
ON dv.fair_id = de.fair_id
AND dv.kpi_date = de.kpi_date;
COMMIT;