Various query cleanups and optimizations based on chats with the team
This commit is contained in:
@ -18,17 +18,27 @@ WITH config AS (
|
|||||||
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
||||||
-- evaluation attempts.
|
-- evaluation attempts.
|
||||||
360 AS long_term,
|
360 AS long_term,
|
||||||
-- We'll only look back a few years since we want to make fairish comparisons betwen users
|
-- We'll only look back a few years since we want to make fairish comparisons between users
|
||||||
-- exposed to "modern" ZenMaid tools.
|
-- exposed to "modern" ZenMaid tools.
|
||||||
CAST('2023-01-01' AS timestamp) AS date_cutoff
|
CAST('2023-01-01' AS timestamp) AS date_cutoff,
|
||||||
|
-- Not all users in our view will have had checklists available during the periods we're looking at,
|
||||||
|
-- so we want to flag each record as having them available or not.
|
||||||
|
CAST('2025-01-01' AS date) AS checklist_available_date
|
||||||
),
|
),
|
||||||
-- Then establish a standard core set of user data
|
-- Then establish a standard core set of user data
|
||||||
users_with_churn_stats AS (
|
users_with_churn_stats AS (
|
||||||
SELECT id, active, billing_state,
|
SELECT id, active, billing_state,
|
||||||
DATE_TRUNC('month', created_at) AS month_created,
|
|
||||||
created_at, free_trial_ends_at, updated_at,
|
created_at, free_trial_ends_at, updated_at,
|
||||||
updated_at::date - created_at::date AS lifespan
|
churned_at, owner.max_owner_updated,
|
||||||
FROM users, config
|
GREATEST(owner.max_owner_updated, users.churned_at) AS last_update,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at)::date - created_at::date AS lifespan
|
||||||
|
FROM config, users
|
||||||
|
JOIN LATERAL (
|
||||||
|
SELECT user_id, max(updated_at) AS max_owner_updated
|
||||||
|
FROM employees
|
||||||
|
WHERE user_id = users.id
|
||||||
|
GROUP BY user_id
|
||||||
|
) owner ON users.id = owner.user_id
|
||||||
-- We'll only look at newish users.
|
-- We'll only look at newish users.
|
||||||
WHERE created_at >= config.date_cutoff
|
WHERE created_at >= config.date_cutoff
|
||||||
),
|
),
|
||||||
@ -89,12 +99,11 @@ users_to_examine AS (
|
|||||||
booking_form_counts AS (
|
booking_form_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT booking_forms.user_id, booking_forms.created_at::date - users.created_at::date AS created_age
|
SELECT booking_forms.user_id, booking_forms.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, booking_forms
|
FROM config, booking_forms
|
||||||
JOIN users ON booking_forms.user_id = users.id
|
JOIN users_to_examine ON booking_forms.user_id = users_to_examine.id
|
||||||
WHERE booking_forms.created_at >= config.date_cutoff
|
WHERE booking_forms.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
AND booking_forms.created_at <= users_to_examine.created_at::date + config.long_term
|
||||||
AND booking_forms.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -127,14 +136,13 @@ booking_form_counts AS (
|
|||||||
booking_counts AS (
|
booking_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT booking_forms.user_id, bookings.created_at::date - users.created_at::date AS created_age
|
SELECT booking_forms.user_id, bookings.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config,
|
FROM config,
|
||||||
booking_forms
|
booking_forms
|
||||||
JOIN users ON booking_forms.user_id = users.id
|
JOIN users_to_examine ON booking_forms.user_id = users_to_examine.id
|
||||||
JOIN bookings ON bookings.booking_form_id = booking_forms.id
|
JOIN bookings ON bookings.booking_form_id = booking_forms.id
|
||||||
WHERE booking_forms.created_at >= config.date_cutoff
|
WHERE booking_forms.created_at >= config.date_cutoff
|
||||||
AND bookings.created_at >= config.date_cutoff
|
AND bookings.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -169,12 +177,11 @@ booking_counts AS (
|
|||||||
employee_counts AS (
|
employee_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT employees.user_id, employees.created_at::date - users.created_at::date AS created_age
|
SELECT employees.user_id, employees.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, employees
|
FROM config, employees
|
||||||
JOIN users ON employees.user_id = users.id
|
JOIN users_to_examine ON employees.user_id = users_to_examine.id
|
||||||
WHERE employees.created_at >= config.date_cutoff
|
WHERE employees.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
AND employees.created_at <= users_to_examine.created_at::date + config.long_term
|
||||||
AND employees.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -207,12 +214,11 @@ employee_counts AS (
|
|||||||
contact_counts AS (
|
contact_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT customers.user_id, customers.created_at::date - users.created_at::date AS created_age
|
SELECT customers.user_id, customers.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, customers
|
FROM config, customers
|
||||||
JOIN users ON customers.user_id = users.id
|
JOIN users_to_examine ON customers.user_id = users_to_examine.id
|
||||||
WHERE customers.created_at >= config.date_cutoff
|
WHERE customers.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
AND customers.created_at <= users_to_examine.created_at::date + config.long_term
|
||||||
AND customers.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -248,7 +254,6 @@ SELECT users_to_examine.id,
|
|||||||
users_to_examine.free_trial_ends_at,
|
users_to_examine.free_trial_ends_at,
|
||||||
users_to_examine.category,
|
users_to_examine.category,
|
||||||
users_to_examine.created_at,
|
users_to_examine.created_at,
|
||||||
users_to_examine.month_created,
|
|
||||||
users_to_examine.updated_at,
|
users_to_examine.updated_at,
|
||||||
users_to_examine.lifespan,
|
users_to_examine.lifespan,
|
||||||
COALESCE(booking_form_counts.short_term, 0) AS booking_forms_short_term,
|
COALESCE(booking_form_counts.short_term, 0) AS booking_forms_short_term,
|
||||||
@ -271,7 +276,7 @@ SELECT users_to_examine.id,
|
|||||||
COALESCE(contact_counts.long_term, 0) AS contacts_long_term,
|
COALESCE(contact_counts.long_term, 0) AS contacts_long_term,
|
||||||
COALESCE(contact_counts.total, 0) AS contacts,
|
COALESCE(contact_counts.total, 0) AS contacts,
|
||||||
COALESCE(contact_counts.weekly_counts, '{}'::jsonb) AS contacts_weekly_counts
|
COALESCE(contact_counts.weekly_counts, '{}'::jsonb) AS contacts_weekly_counts
|
||||||
FROM users_to_examine
|
FROM config, users_to_examine
|
||||||
LEFT JOIN booking_form_counts ON booking_form_counts.user_id = users_to_examine.id
|
LEFT JOIN booking_form_counts ON booking_form_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN booking_counts ON booking_counts.user_id = users_to_examine.id
|
LEFT JOIN booking_counts ON booking_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN employee_counts ON employee_counts.user_id = users_to_examine.id
|
LEFT JOIN employee_counts ON employee_counts.user_id = users_to_examine.id
|
||||||
|
|||||||
@ -18,17 +18,28 @@ WITH config AS (
|
|||||||
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
||||||
-- evaluation attempts.
|
-- evaluation attempts.
|
||||||
360 AS long_term,
|
360 AS long_term,
|
||||||
-- We'll only look back a few years since we want to make fairish comparisons betwen users
|
-- We'll only look back a few years since we want to make fairish comparisons between users
|
||||||
-- exposed to "modern" ZenMaid tools.
|
-- exposed to "modern" ZenMaid tools.
|
||||||
CAST('2023-01-01' AS timestamp) AS date_cutoff
|
CAST('2023-01-01' AS timestamp) AS date_cutoff,
|
||||||
|
-- Not all users in our view will have had checklists available during the periods we're looking at,
|
||||||
|
-- so we want to flag each record as having them available or not.
|
||||||
|
CAST('2025-01-01' AS date) AS checklist_available_date
|
||||||
),
|
),
|
||||||
-- Then establish a standard core set of user data
|
-- Then establish a standard core set of user data
|
||||||
users_with_churn_stats AS (
|
users_with_churn_stats AS (
|
||||||
SELECT id, active, billing_state,
|
SELECT id, active, billing_state,
|
||||||
DATE_TRUNC('month', created_at) AS month_created,
|
|
||||||
created_at, free_trial_ends_at, updated_at,
|
created_at, free_trial_ends_at, updated_at,
|
||||||
updated_at::date - created_at::date AS lifespan
|
churned_at, owner.max_owner_updated,
|
||||||
FROM users, config
|
users.created_at::date + config.long_term AS content_cutoff,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at) AS last_update,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at)::date - created_at::date AS lifespan
|
||||||
|
FROM config, users
|
||||||
|
JOIN LATERAL (
|
||||||
|
SELECT user_id, max(updated_at) AS max_owner_updated
|
||||||
|
FROM employees
|
||||||
|
WHERE user_id = users.id
|
||||||
|
GROUP BY user_id
|
||||||
|
) owner ON users.id = owner.user_id
|
||||||
-- We'll only look at newish users.
|
-- We'll only look at newish users.
|
||||||
WHERE created_at >= config.date_cutoff
|
WHERE created_at >= config.date_cutoff
|
||||||
),
|
),
|
||||||
@ -79,12 +90,10 @@ users_to_examine AS (
|
|||||||
email_counts AS (
|
email_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT sent_emails.user_id, sent_emails.created_at::date - users.created_at::date AS created_age
|
SELECT sent_emails.user_id, sent_emails.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, sent_emails
|
FROM config, sent_emails
|
||||||
JOIN users ON sent_emails.user_id = users.id
|
JOIN users_to_examine ON sent_emails.user_id = users_to_examine.id
|
||||||
WHERE sent_emails.created_at >= config.date_cutoff
|
WHERE sent_emails.created_at <= users_to_examine.content_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
|
||||||
AND sent_emails.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -120,7 +129,6 @@ SELECT users_to_examine.id,
|
|||||||
users_to_examine.free_trial_ends_at,
|
users_to_examine.free_trial_ends_at,
|
||||||
users_to_examine.category,
|
users_to_examine.category,
|
||||||
users_to_examine.created_at,
|
users_to_examine.created_at,
|
||||||
users_to_examine.month_created,
|
|
||||||
users_to_examine.updated_at,
|
users_to_examine.updated_at,
|
||||||
users_to_examine.lifespan,
|
users_to_examine.lifespan,
|
||||||
COALESCE(email_counts.short_term, 0) AS emails_short_term,
|
COALESCE(email_counts.short_term, 0) AS emails_short_term,
|
||||||
@ -128,6 +136,6 @@ SELECT users_to_examine.id,
|
|||||||
COALESCE(email_counts.long_term, 0) AS emails_long_term,
|
COALESCE(email_counts.long_term, 0) AS emails_long_term,
|
||||||
COALESCE(email_counts.total, 0) AS emails,
|
COALESCE(email_counts.total, 0) AS emails,
|
||||||
COALESCE(email_counts.weekly_counts, '{}'::jsonb) AS emails_weekly_counts
|
COALESCE(email_counts.weekly_counts, '{}'::jsonb) AS emails_weekly_counts
|
||||||
FROM users_to_examine
|
FROM config, users_to_examine
|
||||||
LEFT JOIN email_counts ON email_counts.user_id = users_to_examine.id
|
LEFT JOIN email_counts ON email_counts.user_id = users_to_examine.id
|
||||||
;
|
;
|
||||||
|
|||||||
@ -18,17 +18,28 @@ WITH config AS (
|
|||||||
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
||||||
-- evaluation attempts.
|
-- evaluation attempts.
|
||||||
360 AS long_term,
|
360 AS long_term,
|
||||||
-- We'll only look back a few years since we want to make fairish comparisons betwen users
|
-- We'll only look back a few years since we want to make fairish comparisons between users
|
||||||
-- exposed to "modern" ZenMaid tools.
|
-- exposed to "modern" ZenMaid tools.
|
||||||
CAST('2023-01-01' AS timestamp) AS date_cutoff
|
CAST('2023-01-01' AS timestamp) AS date_cutoff,
|
||||||
|
-- Not all users in our view will have had checklists available during the periods we're looking at,
|
||||||
|
-- so we want to flag each record as having them available or not.
|
||||||
|
CAST('2025-01-01' AS date) AS checklist_available_date
|
||||||
),
|
),
|
||||||
-- Then establish a standard core set of user data
|
-- Then establish a standard core set of user data
|
||||||
users_with_churn_stats AS (
|
users_with_churn_stats AS (
|
||||||
SELECT id, active, billing_state,
|
SELECT id, active, billing_state,
|
||||||
DATE_TRUNC('month', created_at) AS month_created,
|
|
||||||
created_at, free_trial_ends_at, updated_at,
|
created_at, free_trial_ends_at, updated_at,
|
||||||
updated_at::date - created_at::date AS lifespan
|
churned_at, owner.max_owner_updated,
|
||||||
FROM users, config
|
users.created_at::date + config.long_term AS content_cutoff,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at) AS last_update,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at)::date - created_at::date AS lifespan
|
||||||
|
FROM config, users
|
||||||
|
JOIN LATERAL (
|
||||||
|
SELECT user_id, max(updated_at) AS max_owner_updated
|
||||||
|
FROM employees
|
||||||
|
WHERE user_id = users.id
|
||||||
|
GROUP BY user_id
|
||||||
|
) owner ON users.id = owner.user_id
|
||||||
-- We'll only look at newish users.
|
-- We'll only look at newish users.
|
||||||
WHERE created_at >= config.date_cutoff
|
WHERE created_at >= config.date_cutoff
|
||||||
),
|
),
|
||||||
@ -79,50 +90,10 @@ users_to_examine AS (
|
|||||||
sms_counts AS (
|
sms_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT sent_texts.user_id, sent_texts.created_at::date - users.created_at::date AS created_age
|
SELECT sent_texts.user_id, sent_texts.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, sent_texts
|
FROM config, sent_texts
|
||||||
JOIN users ON sent_texts.user_id = users.id
|
JOIN users_to_examine ON sent_texts.user_id = users_to_examine.id
|
||||||
WHERE sent_texts.created_at >= config.date_cutoff
|
WHERE sent_texts.created_at <= users_to_examine.content_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
|
||||||
AND sent_texts.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
|
||||||
-- Group by week for line charts
|
|
||||||
weekly_counts AS (
|
|
||||||
SELECT user_id,
|
|
||||||
jsonb_object_agg(
|
|
||||||
'week_' || weeks_in,
|
|
||||||
weekly_count
|
|
||||||
) AS weekly_counts,
|
|
||||||
COUNT(*) AS total
|
|
||||||
FROM (SELECT user_id, FLOOR(created_age / 7) AS weeks_in, COUNT(*) as weekly_count
|
|
||||||
FROM summary
|
|
||||||
GROUP BY user_id, weeks_in) by_weeks
|
|
||||||
GROUP BY user_id
|
|
||||||
),
|
|
||||||
-- Group by era for bar charts
|
|
||||||
bucket_counts AS (
|
|
||||||
SELECT user_id,
|
|
||||||
SUM(CASE WHEN created_age < config.short_term THEN 1 ELSE 0 END) AS short_term,
|
|
||||||
SUM(CASE WHEN created_age >= config.short_term AND created_age < config.medium_term THEN 1 ELSE 0 END) AS medium_term,
|
|
||||||
SUM(CASE WHEN created_age >= config.medium_term AND created_age < config.long_term THEN 1 ELSE 0 END) AS long_term,
|
|
||||||
COUNT(*) AS total
|
|
||||||
FROM config, summary
|
|
||||||
GROUP BY user_id
|
|
||||||
)
|
|
||||||
-- Put it all together
|
|
||||||
SELECT bucket_counts.*, weekly_counts.weekly_counts
|
|
||||||
FROM bucket_counts JOIN weekly_counts ON weekly_counts.user_id = bucket_counts.user_id
|
|
||||||
),
|
|
||||||
-- Appointments by era
|
|
||||||
appointment_counts AS (
|
|
||||||
-- Establish a summary of records with ages
|
|
||||||
WITH summary AS (
|
|
||||||
SELECT appointments.user_id, appointments.created_at::date - users.created_at::date AS created_age
|
|
||||||
FROM config, appointments
|
|
||||||
JOIN users ON appointments.user_id = users.id
|
|
||||||
WHERE appointments.created_at >= config.date_cutoff
|
|
||||||
AND users.created_at >= config.date_cutoff
|
|
||||||
AND appointments.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -158,20 +129,13 @@ SELECT users_to_examine.id,
|
|||||||
users_to_examine.free_trial_ends_at,
|
users_to_examine.free_trial_ends_at,
|
||||||
users_to_examine.category,
|
users_to_examine.category,
|
||||||
users_to_examine.created_at,
|
users_to_examine.created_at,
|
||||||
users_to_examine.month_created,
|
|
||||||
users_to_examine.updated_at,
|
users_to_examine.updated_at,
|
||||||
users_to_examine.lifespan,
|
users_to_examine.lifespan,
|
||||||
COALESCE(sms_counts.short_term, 0) AS sms_short_term,
|
COALESCE(sms_counts.short_term, 0) AS sms_short_term,
|
||||||
COALESCE(sms_counts.medium_term, 0) AS sms_medium_term,
|
COALESCE(sms_counts.medium_term, 0) AS sms_medium_term,
|
||||||
COALESCE(sms_counts.long_term, 0) AS sms_long_term,
|
COALESCE(sms_counts.long_term, 0) AS sms_long_term,
|
||||||
COALESCE(sms_counts.total, 0) AS sms,
|
COALESCE(sms_counts.total, 0) AS sms,
|
||||||
COALESCE(sms_counts.weekly_counts, '{}'::jsonb) AS sms_weekly_counts,
|
COALESCE(sms_counts.weekly_counts, '{}'::jsonb) AS sms_weekly_counts
|
||||||
COALESCE(appointment_counts.short_term, 0) AS appointments_short_term,
|
FROM config, users_to_examine
|
||||||
COALESCE(appointment_counts.medium_term, 0) AS appointments_medium_term,
|
|
||||||
COALESCE(appointment_counts.long_term, 0) AS appointments_long_term,
|
|
||||||
COALESCE(appointment_counts.total, 0) AS appointments,
|
|
||||||
COALESCE(appointment_counts.weekly_counts, '{}'::jsonb) AS appointments_weekly_counts
|
|
||||||
FROM users_to_examine
|
|
||||||
LEFT JOIN sms_counts ON sms_counts.user_id = users_to_examine.id
|
LEFT JOIN sms_counts ON sms_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN appointment_counts ON appointment_counts.user_id = users_to_examine.id
|
|
||||||
;
|
;
|
||||||
|
|||||||
@ -18,17 +18,28 @@ WITH config AS (
|
|||||||
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
||||||
-- evaluation attempts.
|
-- evaluation attempts.
|
||||||
360 AS long_term,
|
360 AS long_term,
|
||||||
-- We'll only look back a few years since we want to make fairish comparisons betwen users
|
-- We'll only look back a few years since we want to make fairish comparisons between users
|
||||||
-- exposed to "modern" ZenMaid tools.
|
-- exposed to "modern" ZenMaid tools.
|
||||||
CAST('2023-01-01' AS timestamp) AS date_cutoff
|
CAST('2023-01-01' AS timestamp) AS date_cutoff,
|
||||||
|
-- Not all users in our view will have had checklists available during the periods we're looking at,
|
||||||
|
-- so we want to flag each record as having them available or not.
|
||||||
|
CAST('2025-01-01' AS date) AS checklist_available_date
|
||||||
),
|
),
|
||||||
-- Then establish a standard core set of user data
|
-- Then establish a standard core set of user data
|
||||||
users_with_churn_stats AS (
|
users_with_churn_stats AS (
|
||||||
SELECT id, active, billing_state,
|
SELECT id, active, billing_state,
|
||||||
DATE_TRUNC('month', created_at) AS month_created,
|
|
||||||
created_at, free_trial_ends_at, updated_at,
|
created_at, free_trial_ends_at, updated_at,
|
||||||
updated_at::date - created_at::date AS lifespan
|
churned_at, owner.max_owner_updated,
|
||||||
FROM users, config
|
users.created_at::date + config.long_term AS content_cutoff,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at) AS last_update,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at)::date - created_at::date AS lifespan
|
||||||
|
FROM config, users
|
||||||
|
JOIN LATERAL (
|
||||||
|
SELECT user_id, max(updated_at) AS max_owner_updated
|
||||||
|
FROM employees
|
||||||
|
WHERE user_id = users.id
|
||||||
|
GROUP BY user_id
|
||||||
|
) owner ON users.id = owner.user_id
|
||||||
-- We'll only look at newish users.
|
-- We'll only look at newish users.
|
||||||
WHERE created_at >= config.date_cutoff
|
WHERE created_at >= config.date_cutoff
|
||||||
),
|
),
|
||||||
@ -75,17 +86,55 @@ users_to_examine AS (
|
|||||||
-- for other reasons like closures, etc.
|
-- for other reasons like closures, etc.
|
||||||
WHERE lifespan >= config.long_term
|
WHERE lifespan >= config.long_term
|
||||||
),
|
),
|
||||||
-- Checklists created by era
|
|
||||||
|
-- Appointments by era
|
||||||
|
appointment_counts AS (
|
||||||
|
-- Establish a summary of records with ages
|
||||||
|
WITH summary AS (
|
||||||
|
SELECT appointments.user_id, appointments.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
|
FROM config, appointments
|
||||||
|
JOIN users_to_examine ON appointments.user_id = users_to_examine.id
|
||||||
|
WHERE appointments.created_at >= config.date_cutoff
|
||||||
|
AND appointments.created_at <= users_to_examine.content_cutoff
|
||||||
|
),
|
||||||
|
-- Group by week for line charts
|
||||||
|
weekly_counts AS (
|
||||||
|
SELECT user_id,
|
||||||
|
jsonb_object_agg(
|
||||||
|
'week_' || weeks_in,
|
||||||
|
weekly_count
|
||||||
|
) AS weekly_counts,
|
||||||
|
COUNT(*) AS total
|
||||||
|
FROM (SELECT user_id, FLOOR(created_age / 7) AS weeks_in, COUNT(*) as weekly_count
|
||||||
|
FROM summary
|
||||||
|
GROUP BY user_id, weeks_in) by_weeks
|
||||||
|
GROUP BY user_id
|
||||||
|
),
|
||||||
|
-- Group by era for bar charts
|
||||||
|
bucket_counts AS (
|
||||||
|
SELECT user_id,
|
||||||
|
SUM(CASE WHEN created_age < config.short_term THEN 1 ELSE 0 END) AS short_term,
|
||||||
|
SUM(CASE WHEN created_age >= config.short_term AND created_age < config.medium_term THEN 1 ELSE 0 END) AS medium_term,
|
||||||
|
SUM(CASE WHEN created_age >= config.medium_term AND created_age < config.long_term THEN 1 ELSE 0 END) AS long_term,
|
||||||
|
COUNT(*) AS total
|
||||||
|
FROM config, summary
|
||||||
|
GROUP BY user_id
|
||||||
|
)
|
||||||
|
-- Put it all together
|
||||||
|
SELECT bucket_counts.*, weekly_counts.weekly_counts
|
||||||
|
FROM bucket_counts JOIN weekly_counts ON weekly_counts.user_id = bucket_counts.user_id
|
||||||
|
),
|
||||||
|
-- Checklists created by era.
|
||||||
checklist_counts AS (
|
checklist_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT checklist_templates.user_id, checklists.created_at::date - users.created_at::date AS created_age
|
SELECT checklist_templates.user_id, checklists.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, checklist_templates
|
FROM config, checklist_templates
|
||||||
JOIN users ON checklist_templates.user_id = users.id
|
JOIN users_to_examine ON checklist_templates.user_id = users_to_examine.id
|
||||||
JOIN checklists ON checklists.checklist_template_id = checklist_templates.id
|
JOIN checklists ON checklists.checklist_template_id = checklist_templates.id
|
||||||
WHERE checklists.created_at >= config.date_cutoff
|
WHERE checklists.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
AND checklists.created_at <= users_to_examine.content_cutoff
|
||||||
AND checklists.created_at <= users.created_at::date + config.long_term
|
AND checklist_templates.parent_id IS NULL -- We only want originals, not new versions.
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -118,13 +167,12 @@ checklist_counts AS (
|
|||||||
checklist_filled_counts AS (
|
checklist_filled_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT employees.user_id, checklist_item_events.created_at::date - users.created_at::date AS created_age
|
SELECT employees.user_id, checklist_item_events.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, employees
|
FROM config, employees
|
||||||
JOIN users ON employees.user_id = users.id
|
JOIN users_to_examine ON employees.user_id = users_to_examine.id
|
||||||
JOIN checklist_item_events ON checklist_item_events.employee_id = employees.id
|
JOIN checklist_item_events ON checklist_item_events.employee_id = employees.id
|
||||||
WHERE checklist_item_events.created_at >= config.date_cutoff
|
WHERE checklist_item_events.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
AND checklist_item_events.created_at <= users_to_examine.content_cutoff
|
||||||
AND checklist_item_events.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -160,13 +208,21 @@ SELECT users_to_examine.id,
|
|||||||
users_to_examine.free_trial_ends_at,
|
users_to_examine.free_trial_ends_at,
|
||||||
users_to_examine.category,
|
users_to_examine.category,
|
||||||
users_to_examine.created_at,
|
users_to_examine.created_at,
|
||||||
users_to_examine.month_created,
|
|
||||||
users_to_examine.updated_at,
|
users_to_examine.updated_at,
|
||||||
users_to_examine.lifespan,
|
users_to_examine.lifespan,
|
||||||
|
COALESCE(appointment_counts.short_term, 0) AS appointments_short_term,
|
||||||
|
COALESCE(appointment_counts.medium_term, 0) AS appointments_medium_term,
|
||||||
|
COALESCE(appointment_counts.long_term, 0) AS appointments_long_term,
|
||||||
|
COALESCE(appointment_counts.total, 0) AS appointments,
|
||||||
|
COALESCE(appointment_counts.weekly_counts, '{}'::jsonb) AS appointments_weekly_counts,
|
||||||
COALESCE(checklist_counts.short_term, 0) AS checklists_short_term,
|
COALESCE(checklist_counts.short_term, 0) AS checklists_short_term,
|
||||||
COALESCE(checklist_counts.medium_term, 0) AS checklists_medium_term,
|
COALESCE(checklist_counts.medium_term, 0) AS checklists_medium_term,
|
||||||
COALESCE(checklist_counts.long_term, 0) AS checklists_long_term,
|
COALESCE(checklist_counts.long_term, 0) AS checklists_long_term,
|
||||||
COALESCE(checklist_counts.total, 0) AS checklists,
|
COALESCE(checklist_counts.total, 0) AS checklists,
|
||||||
|
-- A special field for checklists that lets us know if the user COULD have made a checklist.
|
||||||
|
-- This will be a little weird for users where it was released partway through their critical
|
||||||
|
-- initial usage, but making it more accurate would be too complicated to justify the benefit.
|
||||||
|
users_to_examine.created_at >= config.checklist_available_date - config.medium_term AS checklists_were_available,
|
||||||
COALESCE(checklist_counts.weekly_counts, '{}'::jsonb) AS checklists_weekly_counts,
|
COALESCE(checklist_counts.weekly_counts, '{}'::jsonb) AS checklists_weekly_counts,
|
||||||
COALESCE(checklist_filled_counts.short_term, 0) AS checklists_filled_short_term,
|
COALESCE(checklist_filled_counts.short_term, 0) AS checklists_filled_short_term,
|
||||||
COALESCE(checklist_filled_counts.medium_term, 0) AS checklists_filled_medium_term,
|
COALESCE(checklist_filled_counts.medium_term, 0) AS checklists_filled_medium_term,
|
||||||
@ -174,7 +230,8 @@ SELECT users_to_examine.id,
|
|||||||
COALESCE(checklist_filled_counts.total, 0) AS checklists_filled,
|
COALESCE(checklist_filled_counts.total, 0) AS checklists_filled,
|
||||||
COALESCE(checklist_filled_counts.weekly_counts, '{}'::jsonb) AS checklists_filled_weekly_counts
|
COALESCE(checklist_filled_counts.weekly_counts, '{}'::jsonb) AS checklists_filled_weekly_counts
|
||||||
|
|
||||||
FROM users_to_examine
|
FROM config, users_to_examine
|
||||||
|
LEFT JOIN appointment_counts ON appointment_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN checklist_counts ON checklist_counts.user_id = users_to_examine.id
|
LEFT JOIN checklist_counts ON checklist_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN checklist_filled_counts ON checklist_filled_counts.user_id = users_to_examine.id
|
LEFT JOIN checklist_filled_counts ON checklist_filled_counts.user_id = users_to_examine.id
|
||||||
;
|
;
|
||||||
|
|||||||
@ -18,17 +18,28 @@ WITH config AS (
|
|||||||
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
-- For features, we'll look at this as features used in the company's day-to-day, and not
|
||||||
-- evaluation attempts.
|
-- evaluation attempts.
|
||||||
360 AS long_term,
|
360 AS long_term,
|
||||||
-- We'll only look back a few years since we want to make fairish comparisons betwen users
|
-- We'll only look back a few years since we want to make fairish comparisons between users
|
||||||
-- exposed to "modern" ZenMaid tools.
|
-- exposed to "modern" ZenMaid tools.
|
||||||
CAST('2023-01-01' AS timestamp) AS date_cutoff
|
CAST('2023-01-01' AS timestamp) AS date_cutoff,
|
||||||
|
-- Not all users in our view will have had checklists available during the periods we're looking at,
|
||||||
|
-- so we want to flag each record as having them available or not.
|
||||||
|
CAST('2025-01-01' AS date) AS checklist_available_date
|
||||||
),
|
),
|
||||||
-- Then establish a standard core set of user data
|
-- Then establish a standard core set of user data
|
||||||
users_with_churn_stats AS (
|
users_with_churn_stats AS (
|
||||||
SELECT id, active, billing_state,
|
SELECT id, active, billing_state,
|
||||||
DATE_TRUNC('month', created_at) AS month_created,
|
|
||||||
created_at, free_trial_ends_at, updated_at,
|
created_at, free_trial_ends_at, updated_at,
|
||||||
updated_at::date - created_at::date AS lifespan
|
churned_at, owner.max_owner_updated,
|
||||||
FROM users, config
|
users.created_at::date + config.long_term AS content_cutoff,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at) AS last_update,
|
||||||
|
GREATEST(owner.max_owner_updated, users.churned_at)::date - created_at::date AS lifespan
|
||||||
|
FROM config, users
|
||||||
|
JOIN LATERAL (
|
||||||
|
SELECT user_id, max(updated_at) AS max_owner_updated
|
||||||
|
FROM employees
|
||||||
|
WHERE user_id = users.id
|
||||||
|
GROUP BY user_id
|
||||||
|
) owner ON users.id = owner.user_id
|
||||||
-- We'll only look at newish users.
|
-- We'll only look at newish users.
|
||||||
WHERE created_at >= config.date_cutoff
|
WHERE created_at >= config.date_cutoff
|
||||||
),
|
),
|
||||||
@ -89,12 +100,11 @@ users_to_examine AS (
|
|||||||
booking_form_counts AS (
|
booking_form_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT booking_forms.user_id, booking_forms.created_at::date - users.created_at::date AS created_age
|
SELECT booking_forms.user_id, booking_forms.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, booking_forms
|
FROM config, booking_forms
|
||||||
JOIN users ON booking_forms.user_id = users.id
|
JOIN users_to_examine ON booking_forms.user_id = users_to_examine.id
|
||||||
WHERE booking_forms.created_at >= config.date_cutoff
|
WHERE booking_forms.created_at >= users_to_examine.created_at
|
||||||
AND users.created_at >= config.date_cutoff
|
AND booking_forms.created_at <= users_to_examine.content_cutoff
|
||||||
AND booking_forms.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -127,14 +137,14 @@ booking_form_counts AS (
|
|||||||
booking_counts AS (
|
booking_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT booking_forms.user_id, bookings.created_at::date - users.created_at::date AS created_age
|
SELECT booking_forms.user_id, bookings.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config,
|
FROM config,
|
||||||
booking_forms
|
booking_forms
|
||||||
JOIN users ON booking_forms.user_id = users.id
|
JOIN users_to_examine ON booking_forms.user_id = users_to_examine.id
|
||||||
JOIN bookings ON bookings.booking_form_id = booking_forms.id
|
JOIN bookings ON bookings.booking_form_id = booking_forms.id
|
||||||
WHERE booking_forms.created_at >= config.date_cutoff
|
WHERE booking_forms.created_at >= users_to_examine.created_at
|
||||||
AND bookings.created_at >= config.date_cutoff
|
AND bookings.created_at >= users_to_examine.created_at
|
||||||
AND users.created_at >= config.date_cutoff
|
AND bookings.created_at <= users_to_examine.content_cutoff
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -169,12 +179,11 @@ booking_counts AS (
|
|||||||
employee_counts AS (
|
employee_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT employees.user_id, employees.created_at::date - users.created_at::date AS created_age
|
SELECT employees.user_id, employees.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, employees
|
FROM config, employees
|
||||||
JOIN users ON employees.user_id = users.id
|
JOIN users_to_examine ON employees.user_id = users_to_examine.id
|
||||||
WHERE employees.created_at >= config.date_cutoff
|
WHERE employees.created_at >= users_to_examine.created_at
|
||||||
AND users.created_at >= config.date_cutoff
|
AND employees.created_at <= users_to_examine.content_cutoff
|
||||||
AND employees.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -207,12 +216,11 @@ employee_counts AS (
|
|||||||
contact_counts AS (
|
contact_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT customers.user_id, customers.created_at::date - users.created_at::date AS created_age
|
SELECT customers.user_id, customers.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, customers
|
FROM config, customers
|
||||||
JOIN users ON customers.user_id = users.id
|
JOIN users_to_examine ON customers.user_id = users_to_examine.id
|
||||||
WHERE customers.created_at >= config.date_cutoff
|
WHERE customers.created_at >= users_to_examine.created_at
|
||||||
AND users.created_at >= config.date_cutoff
|
AND customers.created_at <= users_to_examine.content_cutoff
|
||||||
AND customers.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -245,12 +253,10 @@ contact_counts AS (
|
|||||||
email_counts AS (
|
email_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT sent_emails.user_id, sent_emails.created_at::date - users.created_at::date AS created_age
|
SELECT sent_emails.user_id, sent_emails.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, sent_emails
|
FROM config, sent_emails
|
||||||
JOIN users ON sent_emails.user_id = users.id
|
JOIN users_to_examine ON sent_emails.user_id = users_to_examine.id
|
||||||
WHERE sent_emails.created_at >= config.date_cutoff
|
WHERE sent_emails.created_at <= users_to_examine.content_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
|
||||||
AND sent_emails.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -283,12 +289,10 @@ email_counts AS (
|
|||||||
sms_counts AS (
|
sms_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT sent_texts.user_id, sent_texts.created_at::date - users.created_at::date AS created_age
|
SELECT sent_texts.user_id, sent_texts.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, sent_texts
|
FROM config, sent_texts
|
||||||
JOIN users ON sent_texts.user_id = users.id
|
JOIN users_to_examine ON sent_texts.user_id = users_to_examine.id
|
||||||
WHERE sent_texts.created_at >= config.date_cutoff
|
WHERE sent_texts.created_at <= users_to_examine.content_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
|
||||||
AND sent_texts.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -321,12 +325,11 @@ sms_counts AS (
|
|||||||
appointment_counts AS (
|
appointment_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT appointments.user_id, appointments.created_at::date - users.created_at::date AS created_age
|
SELECT appointments.user_id, appointments.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, appointments
|
FROM config, appointments
|
||||||
JOIN users ON appointments.user_id = users.id
|
JOIN users_to_examine ON appointments.user_id = users_to_examine.id
|
||||||
WHERE appointments.created_at >= config.date_cutoff
|
WHERE appointments.created_at >= users_to_examine.created_at
|
||||||
AND users.created_at >= config.date_cutoff
|
AND appointments.created_at <= users_to_examine.content_cutoff
|
||||||
AND appointments.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -355,17 +358,17 @@ appointment_counts AS (
|
|||||||
SELECT bucket_counts.*, weekly_counts.weekly_counts
|
SELECT bucket_counts.*, weekly_counts.weekly_counts
|
||||||
FROM bucket_counts JOIN weekly_counts ON weekly_counts.user_id = bucket_counts.user_id
|
FROM bucket_counts JOIN weekly_counts ON weekly_counts.user_id = bucket_counts.user_id
|
||||||
),
|
),
|
||||||
-- Checklists created by era
|
-- Checklists created by era.
|
||||||
checklist_counts AS (
|
checklist_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT checklist_templates.user_id, checklists.created_at::date - users.created_at::date AS created_age
|
SELECT checklist_templates.user_id, checklists.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, checklist_templates
|
FROM config, checklist_templates
|
||||||
JOIN users ON checklist_templates.user_id = users.id
|
JOIN users_to_examine ON checklist_templates.user_id = users_to_examine.id
|
||||||
JOIN checklists ON checklists.checklist_template_id = checklist_templates.id
|
JOIN checklists ON checklists.checklist_template_id = checklist_templates.id
|
||||||
WHERE checklists.created_at >= config.date_cutoff
|
WHERE checklists.created_at >= users_to_examine.created_at
|
||||||
AND users.created_at >= config.date_cutoff
|
AND checklists.created_at <= users_to_examine.content_cutoff
|
||||||
AND checklists.created_at <= users.created_at::date + config.long_term
|
AND checklist_templates.parent_id IS NULL -- We only want originals, not new versions.
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -398,13 +401,12 @@ checklist_counts AS (
|
|||||||
checklist_filled_counts AS (
|
checklist_filled_counts AS (
|
||||||
-- Establish a summary of records with ages
|
-- Establish a summary of records with ages
|
||||||
WITH summary AS (
|
WITH summary AS (
|
||||||
SELECT employees.user_id, checklist_item_events.created_at::date - users.created_at::date AS created_age
|
SELECT employees.user_id, checklist_item_events.created_at::date - users_to_examine.created_at::date AS created_age
|
||||||
FROM config, employees
|
FROM config, employees
|
||||||
JOIN users ON employees.user_id = users.id
|
JOIN users_to_examine ON employees.user_id = users_to_examine.id
|
||||||
JOIN checklist_item_events ON checklist_item_events.employee_id = employees.id
|
JOIN checklist_item_events ON checklist_item_events.employee_id = employees.id
|
||||||
WHERE checklist_item_events.created_at >= config.date_cutoff
|
WHERE checklist_item_events.created_at >= config.date_cutoff
|
||||||
AND users.created_at >= config.date_cutoff
|
AND checklist_item_events.created_at <= users_to_examine.content_cutoff
|
||||||
AND checklist_item_events.created_at <= users.created_at::date + config.long_term
|
|
||||||
),
|
),
|
||||||
-- Group by week for line charts
|
-- Group by week for line charts
|
||||||
weekly_counts AS (
|
weekly_counts AS (
|
||||||
@ -440,7 +442,6 @@ SELECT users_to_examine.id,
|
|||||||
users_to_examine.free_trial_ends_at,
|
users_to_examine.free_trial_ends_at,
|
||||||
users_to_examine.category,
|
users_to_examine.category,
|
||||||
users_to_examine.created_at,
|
users_to_examine.created_at,
|
||||||
users_to_examine.month_created,
|
|
||||||
users_to_examine.updated_at,
|
users_to_examine.updated_at,
|
||||||
users_to_examine.lifespan,
|
users_to_examine.lifespan,
|
||||||
COALESCE(booking_form_counts.short_term, 0) AS booking_forms_short_term,
|
COALESCE(booking_form_counts.short_term, 0) AS booking_forms_short_term,
|
||||||
@ -482,6 +483,10 @@ SELECT users_to_examine.id,
|
|||||||
COALESCE(checklist_counts.medium_term, 0) AS checklists_medium_term,
|
COALESCE(checklist_counts.medium_term, 0) AS checklists_medium_term,
|
||||||
COALESCE(checklist_counts.long_term, 0) AS checklists_long_term,
|
COALESCE(checklist_counts.long_term, 0) AS checklists_long_term,
|
||||||
COALESCE(checklist_counts.total, 0) AS checklists,
|
COALESCE(checklist_counts.total, 0) AS checklists,
|
||||||
|
-- A special field for checklists that lets us know if the user COULD have made a checklist.
|
||||||
|
-- This will be a little weird for users where it was released partway through their critical
|
||||||
|
-- initial usage, but making it more accurate would be too complicated to justify the benefit.
|
||||||
|
users_to_examine.created_at >= config.checklist_available_date - config.medium_term AS checklists_were_available,
|
||||||
COALESCE(checklist_counts.weekly_counts, '{}'::jsonb) AS checklists_weekly_counts,
|
COALESCE(checklist_counts.weekly_counts, '{}'::jsonb) AS checklists_weekly_counts,
|
||||||
COALESCE(checklist_filled_counts.short_term, 0) AS checklists_filled_short_term,
|
COALESCE(checklist_filled_counts.short_term, 0) AS checklists_filled_short_term,
|
||||||
COALESCE(checklist_filled_counts.medium_term, 0) AS checklists_filled_medium_term,
|
COALESCE(checklist_filled_counts.medium_term, 0) AS checklists_filled_medium_term,
|
||||||
@ -489,7 +494,7 @@ SELECT users_to_examine.id,
|
|||||||
COALESCE(checklist_filled_counts.total, 0) AS checklists_filled,
|
COALESCE(checklist_filled_counts.total, 0) AS checklists_filled,
|
||||||
COALESCE(checklist_filled_counts.weekly_counts, '{}'::jsonb) AS checklists_filled_weekly_counts
|
COALESCE(checklist_filled_counts.weekly_counts, '{}'::jsonb) AS checklists_filled_weekly_counts
|
||||||
|
|
||||||
FROM users_to_examine
|
FROM config, users_to_examine
|
||||||
LEFT JOIN booking_form_counts ON booking_form_counts.user_id = users_to_examine.id
|
LEFT JOIN booking_form_counts ON booking_form_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN booking_counts ON booking_counts.user_id = users_to_examine.id
|
LEFT JOIN booking_counts ON booking_counts.user_id = users_to_examine.id
|
||||||
LEFT JOIN employee_counts ON employee_counts.user_id = users_to_examine.id
|
LEFT JOIN employee_counts ON employee_counts.user_id = users_to_examine.id
|
||||||
|
|||||||
25181
churn-analysis.ipynb
25181
churn-analysis.ipynb
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user