diff --git a/models/marts/reporting/rep_exchange__cohort_analysis.sql b/models/marts/reporting/rep_exchange__cohort_analysis.sql new file mode 100644 index 0000000..93227cb --- /dev/null +++ b/models/marts/reporting/rep_exchange__cohort_analysis.sql @@ -0,0 +1,187 @@ +-- SOURCE: https://www.holistics.io/blog/calculate-cohort-retention-analysis-with-sql/ + +-- IMPORT +WITH companies AS ( + SELECT * FROM {{ ref('dim_exchange__companies') }} +), + +transaction_orders AS ( + SELECT * FROM {{ ref('fct_exchange__transaction_orders') }} +), + + +-- LOGIC +company_register_month_year AS ( + + SELECT + companies.company_id, + companies.company_created_datetime, + IFF(MAX(transaction_orders.order_created_datetime) IS NULL, 1, 0) AS is_never_order_company, + DATE(DATE_TRUNC('MONTH', companies.company_created_datetime)) AS register_month_year, + DATE(DATE_TRUNC('MONTH', MIN(transaction_orders.order_created_datetime))) AS first_order_month_year + + FROM companies + + LEFT JOIN transaction_orders + ON (companies.company_id = transaction_orders.company_id) + + GROUP BY + companies.company_id, + companies.company_created_datetime, + register_month_year + +), + +-- Identify orders placed from each company, from the time of company registration +-- In cohort analysis, we do not consider number of orders by each user, just whether has_placed_orders or not_placed_orders in each month +company_order_count_from_registration_date AS ( + + SELECT + transaction_orders.company_id, + DATEDIFF(MONTH, company_register_month_year.company_created_datetime, transaction_orders.order_created_datetime) AS order_month + + FROM transaction_orders + + LEFT JOIN company_register_month_year + ON (transaction_orders.company_id = company_register_month_year.company_id) + + GROUP BY + transaction_orders.company_id, + order_month + +), + +company_first_order_count_from_registration_date AS ( + + SELECT + transaction_orders.company_id, + DATE(DATE_TRUNC('MONTH', company_created_datetime)) AS company_created_datetime, + MIN(DATEDIFF(MONTH, company_register_month_year.company_created_datetime, transaction_orders.order_created_datetime)) AS first_order_month + + FROM transaction_orders + + LEFT JOIN company_register_month_year + ON (transaction_orders.company_id = company_register_month_year.company_id) + + GROUP BY + transaction_orders.company_id, + company_created_datetime + +), + +cohort_size_by_month_year AS ( + + SELECT + register_month_year, + SUM(is_never_order_company) AS count_never_order_companies, + COUNT(register_month_year) AS count_total_companies + + FROM company_register_month_year + + GROUP BY register_month_year + + ORDER BY register_month_year + +), + +order_retention AS ( + + SELECT + company_register_month_year.register_month_year, + company_order_count_from_registration_date.order_month, + COUNT(company_register_month_year.register_month_year) AS count_retained_companies + + FROM company_order_count_from_registration_date + + LEFT JOIN company_register_month_year + ON (company_order_count_from_registration_date.company_id = company_register_month_year.company_id) + + GROUP BY + company_register_month_year.register_month_year, + company_order_count_from_registration_date.order_month +), + +first_time_order_retention AS ( + SELECT + company_created_datetime, + first_order_month, + COUNT(first_order_month) AS count_first_order_companies + + FROM company_first_order_count_from_registration_date + + GROUP BY + company_created_datetime, + first_order_month + +), + +cohort_analysis_table AS ( + + SELECT + order_retention.register_month_year, + order_retention.order_month, + order_retention.count_retained_companies AS retained_companies, + + cohort_size_by_month_year.count_total_companies AS total_registered_company, + cohort_size_by_month_year.count_never_order_companies, + + first_time_order_retention.count_first_order_companies AS count_first_order_companies, + + DIV0( + retained_companies, + total_registered_company + ) AS retention_rate_overall, + + DIV0( + retained_companies, + ( total_registered_company - cohort_size_by_month_year.count_never_order_companies ) + ) AS retention_rate_exclude_never_order_company, + + DIV0( + count_first_order_companies, + ( total_registered_company - count_never_order_companies ) + ) AS first_order_percentage, + + '{{ modules.datetime.datetime.now(modules.pytz.timezone("Asia/Kuala_Lumpur")) }}' AS _dbt_ran_datetime + + FROM order_retention + + LEFT JOIN cohort_size_by_month_year + ON (order_retention.register_month_year = cohort_size_by_month_year.register_month_year) + + LEFT JOIN first_time_order_retention + ON (order_retention.register_month_year = first_time_order_retention.company_created_datetime) + AND (order_retention.order_month = first_time_order_retention.first_order_month) + + ORDER BY + order_retention.register_month_year, + order_retention.order_month + +), + + +-- FINAL +final_rep_exchange__cohort_analysis AS ( + + SELECT + -- dimensions + register_month_year, + total_registered_company, + order_month, + + -- measures + count_never_order_companies, + count_first_order_companies, + retained_companies, + retention_rate_overall, + retention_rate_exclude_never_order_company, + first_order_percentage, + + -- metadata + _dbt_ran_datetime + + FROM cohort_analysis_table + +) + +SELECT * FROM final_rep_exchange__cohort_analysis \ No newline at end of file