SQL
Marketing platform
Monthly Engagement Churn
Monthly Engagement Churn model for marketing platform.
source-preserved
Blocks
monthly_engagement_churn.sql · 58 lines
inferred
-- models/monthly_engagement_churn.sql
{{ config(materialized='view') }}
/* find all engagements */
with (
select distinct date_trunc('day',e.created_at) as day, e.member_id as id
from engagements e
where
{% condition date_month %} e.created_at {% endcondition %} and
{% condition date_week %} e.created_at {% endcondition %} and
{% condition date_date %} e.created_at {% endcondition %}
group by 1,2
) as e
(
/* churned - find all engagements where there is no enagagement within the next 30 days */
select e.day as date, e.id, 'churned_at' as type from e
left join e e2 on e.id=e2.id and e2.day >e.day and e2.day < e.day + interval '30 days'
where e2.day is null
) union (
/* reengaged - find all engagements where the previous engagement was more than 30 days ago */
select e.day as date, e.id, 'reengaged_at' as type from e
left join e e2 on e.id=e2.id and e2.day < e.day and e2.day >= e.day - interval '30 days'
left join e e3 on e.id=e3.id and e3.day < e.day - interval '30 days'
where e2.day is null and e3.day is not null
) union (
/* created - just find all campaign_new users */
select min(m.created_at) as date,
m.id,
'created_at' as type
from users m
group by 2
) union (
/* "bounced" = find all campaign_new users with no engagements */
select
min(m.created_at) as date,
m.id,
'bounced_at' as type
from users m
where not exists (select 1 from engagements e where e.member_id = m.id limit 1)
group by 2
) union (
/* engaged - just find all engaged users */
select
e.day,
e.id,
'engaged_at' as type
from e
)
# models/schema.yml
version: 2
models:
- name: monthly_engagement_churn
columns:
- name: type
- name: date
- name: id
Assumptions
- materialized='view' is the default; no persist hint found.
- schema.yml columns come from view dimensions; a primary_key dimension gets unique + not_null tests.
monthly_engagement_churn.sql · 45 lines
source-preserved
validation: not checked
/* find all engagements */
with (
select distinct date_trunc('day',e.created_at) as day, e.member_id as id
from engagements e
where
{% condition date_month %} e.created_at {% endcondition %} and
{% condition date_week %} e.created_at {% endcondition %} and
{% condition date_date %} e.created_at {% endcondition %}
group by 1,2
) as e
(
/* churned - find all engagements where there is no enagagement within the next 30 days */
select e.day as date, e.id, 'churned_at' as type from e
left join e e2 on e.id=e2.id and e2.day >e.day and e2.day < e.day + interval '30 days'
where e2.day is null
) union (
/* reengaged - find all engagements where the previous engagement was more than 30 days ago */
select e.day as date, e.id, 'reengaged_at' as type from e
left join e e2 on e.id=e2.id and e2.day < e.day and e2.day >= e.day - interval '30 days'
left join e e3 on e.id=e3.id and e3.day < e.day - interval '30 days'
where e2.day is null and e3.day is not null
) union (
/* created - just find all campaign_new users */
select min(m.created_at) as date,
m.id,
'created_at' as type
from users m
group by 2
) union (
/* "bounced" = find all campaign_new users with no engagements */
select
min(m.created_at) as date,
m.id,
'bounced_at' as type
from users m
where not exists (select 1 from engagements e where e.member_id = m.id limit 1)
group by 2
) union (
/* engaged - just find all engaged users */
select
e.day,
e.id,
'engaged_at' as type
from e
)
monthly_engagement_churn.view.lkml · 92 lines
inferred
view: monthly_engagement_churn {
derived_table: {
sql: /* find all engagements */
with (
select distinct date_trunc('day',e.created_at) as day, e.member_id as id
from engagements e
where
{% condition date_month %} e.created_at {% endcondition %} and
{% condition date_week %} e.created_at {% endcondition %} and
{% condition date_date %} e.created_at {% endcondition %}
group by 1,2
) as e
(
/* churned - find all engagements where there is no enagagement within the next 30 days */
select e.day as date, e.id, 'churned_at' as type from e
left join e e2 on e.id=e2.id and e2.day >e.day and e2.day < e.day + interval '30 days'
where e2.day is null
) union (
/* reengaged - find all engagements where the previous engagement was more than 30 days ago */
select e.day as date, e.id, 'reengaged_at' as type from e
left join e e2 on e.id=e2.id and e2.day < e.day and e2.day >= e.day - interval '30 days'
left join e e3 on e.id=e3.id and e3.day < e.day - interval '30 days'
where e2.day is null and e3.day is not null
) union (
/* created - just find all campaign_new users */
select min(m.created_at) as date,
m.id,
'created_at' as type
from users m
group by 2
) union (
/* "bounced" = find all campaign_new users with no engagements */
select
min(m.created_at) as date,
m.id,
'bounced_at' as type
from users m
where not exists (select 1 from engagements e where e.member_id = m.id limit 1)
group by 2
) union (
/* engaged - just find all engaged users */
select
e.day,
e.id,
'engaged_at' as type
from e
) ;;
}
dimension: type {
sql: ${TABLE}.type ;;
}
dimension: date {
type: time
sql: ${TABLE}.date ;;
}
dimension: id {
sql: ${TABLE}.id ;;
}
measure: bounced {
description: "campaign_new members who signed this date and have no engagements"
type: count_distinct
sql: case when type='bounced_at' then ${id} else null end ;;
}
measure: churned {
description: "members who have an engagement now but none in the next 30 days"
type: count_distinct
sql: case when type='churned_at' then ${id} else null end ;;
}
measure: reengaged {
description: "members who have an engagement before 30 days ago, none between now and 30 days ago, and now have a campaign_new engagement"
type: count_distinct
sql: case when type='reengaged_at' then ${id} else null end ;;
}
measure: engaged {
description: "members who have an engagement"
type: count_distinct
sql: case when type='engaged_at' then ${id} else null end ;;
}
measure: campaign_new {
description: "campaign_new members who signed this date"
type: count_distinct
sql: case when type='created_at' then ${id} else null end ;;
}
}
monthly_engagement_churn.view.lookml · 75 lines
source-preserved
- view: monthly_engagement_churn
derived_table:
sql: /* find all engagements */
with (
select distinct date_trunc('day',e.created_at) as day, e.member_id as id
from engagements e
where
{% condition date_month %} e.created_at {% endcondition %} and
{% condition date_week %} e.created_at {% endcondition %} and
{% condition date_date %} e.created_at {% endcondition %}
group by 1,2
) as e
(
/* churned - find all engagements where there is no enagagement within the next 30 days */
select e.day as date, e.id, 'churned_at' as type from e
left join e e2 on e.id=e2.id and e2.day >e.day and e2.day < e.day + interval '30 days'
where e2.day is null
) union (
/* reengaged - find all engagements where the previous engagement was more than 30 days ago */
select e.day as date, e.id, 'reengaged_at' as type from e
left join e e2 on e.id=e2.id and e2.day < e.day and e2.day >= e.day - interval '30 days'
left join e e3 on e.id=e3.id and e3.day < e.day - interval '30 days'
where e2.day is null and e3.day is not null
) union (
/* created - just find all campaign_new users */
select min(m.created_at) as date,
m.id,
'created_at' as type
from users m
group by 2
) union (
/* "bounced" = find all campaign_new users with no engagements */
select
min(m.created_at) as date,
m.id,
'bounced_at' as type
from users m
where not exists (select 1 from engagements e where e.member_id = m.id limit 1)
group by 2
) union (
/* engaged - just find all engaged users */
select
e.day,
e.id,
'engaged_at' as type
from e
)
fields:
- dimension: type
sql: ${TABLE}.type
- dimension: date
type: time
sql: ${TABLE}.date
- dimension: id
sql: ${TABLE}.id
- measure: bounced
type: count_distinct
description: campaign_new members who signed this date and have no engagements
sql: case when type='bounced_at' then ${id} else null end
- measure: churned
type: count_distinct
description: members who have an engagement now but none in the next 30 days
sql: case when type='churned_at' then ${id} else null end
- measure: reengaged
type: count_distinct
description: members who have an engagement before 30 days ago, none between now and 30 days ago, and now have a campaign_new engagement
sql: case when type='reengaged_at' then ${id} else null end
- measure: engaged
type: count_distinct
description: members who have an engagement
sql: case when type='engaged_at' then ${id} else null end
- measure: campaign_new
type: count_distinct
description: campaign_new members who signed this date
sql: case when type='created_at' then ${id} else null end
Contents
- monthly_engagement_churn.sql
- monthly_engagement_churn.sql
- monthly_engagement_churn.view.lkml
- monthly_engagement_churn.view.lookml