Files
vps_web/docs/forum-post-detail-funnel-sql.md
ddrwode d454699f50 哈哈
2026-02-11 17:38:06 +08:00

166 lines
5.6 KiB
Markdown

# Forum Post Detail Funnel SQL
This project now stores tracking events in table `forum_track_events`.
Daily rollup is also available in `forum_track_daily_summary`.
Key columns:
- `event_name`
- `label`
- `post_id`
- `user_id`
- `visitor_id`
- `cta_variant`
- `created_at`
Use the queries below as baseline funnel cuts.
## 1) Daily impression -> pricing CTA conversion (MySQL)
```sql
SELECT
DATE(created_at) AS d,
COALESCE(cta_variant, 'unknown') AS cta_variant,
COUNT(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 END) AS impressions,
COUNT(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 END) AS pricing_clicks,
ROUND(
COUNT(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 END) * 100.0
/ NULLIF(COUNT(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 END), 0),
2
) AS ctr_pct
FROM forum_track_events
WHERE created_at >= NOW() - INTERVAL 30 DAY
GROUP BY DATE(created_at), COALESCE(cta_variant, 'unknown')
ORDER BY d DESC, cta_variant;
```
## 2) Unique visitor funnel by variant (MySQL)
```sql
WITH pv AS (
SELECT
COALESCE(NULLIF(visitor_id, ''), CONCAT('u:', user_id)) AS actor_id,
COALESCE(cta_variant, 'unknown') AS cta_variant,
MAX(event_name = 'post_detail_cta_impression') AS seen_impression,
MAX(event_name = 'post_detail_cta_pricing') AS clicked_pricing,
MAX(event_name = 'post_detail_comment_submit') AS submitted_comment
FROM forum_track_events
WHERE created_at >= NOW() - INTERVAL 30 DAY
GROUP BY COALESCE(NULLIF(visitor_id, ''), CONCAT('u:', user_id)), COALESCE(cta_variant, 'unknown')
)
SELECT
cta_variant,
COUNT(*) AS actors,
SUM(seen_impression) AS actors_with_impression,
SUM(clicked_pricing) AS actors_with_pricing_click,
SUM(submitted_comment) AS actors_with_comment,
ROUND(SUM(clicked_pricing) * 100.0 / NULLIF(SUM(seen_impression), 0), 2) AS actor_ctr_pct,
ROUND(SUM(submitted_comment) * 100.0 / NULLIF(SUM(seen_impression), 0), 2) AS actor_comment_rate_pct
FROM pv
GROUP BY cta_variant
ORDER BY cta_variant;
```
## 3) Top performing CTA labels (MySQL)
```sql
SELECT
label,
COUNT(*) AS clicks
FROM forum_track_events
WHERE event_name IN ('post_detail_cta_pricing', 'post_detail_cta_new_topic', 'post_detail_sidebar_compare')
AND created_at >= NOW() - INTERVAL 30 DAY
GROUP BY label
ORDER BY clicks DESC
LIMIT 20;
```
## 4) Daily impression -> pricing CTA conversion (SQLite)
```sql
SELECT
DATE(created_at) AS d,
COALESCE(cta_variant, 'unknown') AS cta_variant,
SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END) AS impressions,
SUM(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 ELSE 0 END) AS pricing_clicks,
ROUND(
SUM(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 ELSE 0 END) * 100.0
/ NULLIF(SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END), 0),
2
) AS ctr_pct
FROM forum_track_events
WHERE created_at >= DATETIME('now', '-30 days')
GROUP BY DATE(created_at), COALESCE(cta_variant, 'unknown')
ORDER BY d DESC, cta_variant;
```
## 5) Post-level conversion ranking (SQLite/MySQL compatible style)
```sql
SELECT
post_id,
COALESCE(cta_variant, 'unknown') AS cta_variant,
SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END) AS impressions,
SUM(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 ELSE 0 END) AS pricing_clicks,
ROUND(
SUM(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 ELSE 0 END) * 100.0
/ NULLIF(SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END), 0),
2
) AS ctr_pct
FROM forum_track_events
WHERE post_id IS NOT NULL
GROUP BY post_id, COALESCE(cta_variant, 'unknown')
HAVING impressions >= 20
ORDER BY ctr_pct DESC, impressions DESC
LIMIT 50;
```
## 6) Daily rollup table quick check (SQLite/MySQL compatible style)
```sql
SELECT
event_day,
cta_variant,
event_name,
total
FROM forum_track_daily_summary
WHERE event_day >= DATE('now', '-30 day') -- MySQL: CURDATE() - INTERVAL 30 DAY
ORDER BY event_day DESC, cta_variant, event_name;
```
## 7) Mobile sticky-bar exposure rate (SQLite/MySQL compatible style)
```sql
SELECT
DATE(created_at) AS d,
COALESCE(cta_variant, 'unknown') AS cta_variant,
SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END) AS impressions,
SUM(CASE WHEN event_name = 'post_detail_mobile_bar_impression' THEN 1 ELSE 0 END) AS mobile_bar_impressions,
ROUND(
SUM(CASE WHEN event_name = 'post_detail_mobile_bar_impression' THEN 1 ELSE 0 END) * 100.0
/ NULLIF(SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END), 0),
2
) AS mobile_bar_exposure_pct
FROM forum_track_events
WHERE created_at >= DATETIME('now', '-30 days')
GROUP BY DATE(created_at), COALESCE(cta_variant, 'unknown')
ORDER BY d DESC, cta_variant;
```
## 8) Device split performance (SQLite/MySQL compatible style)
```sql
SELECT
DATE(created_at) AS d,
COALESCE(device_type, 'unknown') AS device_type,
COALESCE(cta_variant, 'unknown') AS cta_variant,
SUM(CASE WHEN event_name = 'post_detail_cta_impression' THEN 1 ELSE 0 END) AS impressions,
SUM(CASE WHEN event_name = 'post_detail_mobile_bar_impression' THEN 1 ELSE 0 END) AS mobile_bar_impressions,
SUM(CASE WHEN event_name = 'post_detail_cta_pricing' THEN 1 ELSE 0 END) AS pricing_clicks,
SUM(CASE WHEN event_name = 'post_detail_cta_pricing' AND label LIKE 'mobile_%' THEN 1 ELSE 0 END) AS mobile_pricing_clicks
FROM forum_track_events
WHERE created_at >= DATETIME('now', '-30 days')
GROUP BY DATE(created_at), COALESCE(device_type, 'unknown'), COALESCE(cta_variant, 'unknown')
ORDER BY d DESC, device_type, cta_variant;
```