sql/moz-fx-data-shared-prod/stripe_external/subscriptions_changelog_v1/query.sql (298 lines of code) (raw):

WITH subscriptions_history AS ( SELECT -- Synthesize a primary key column to make identifying rows and doing joins easier. CONCAT(id, '-', FORMAT_TIMESTAMP('%FT%H:%M:%E6S', _fivetran_start)) AS id, id AS subscription_id, _fivetran_synced, _fivetran_start, _fivetran_active, billing_cycle_anchor, cancel_at, cancel_at_period_end, canceled_at, -- `billing` was renamed `collection_method`. COALESCE(collection_method, billing) AS collection_method, created, current_period_end, current_period_start, customer_id, days_until_due, default_payment_method_id, default_source_id, ended_at, latest_invoice_id, PARSE_JSON(metadata) AS metadata, pending_setup_intent_id, start_date, status, trial_end, trial_start, FROM `moz-fx-data-shared-prod`.stripe_external.subscription_history_v1 ), new_subscriptions_history AS ( {% if is_init() %} SELECT * FROM subscriptions_history {% else %} WITH latest_subscriptions_changelog AS ( SELECT subscription.id AS subscription_id, MAX(`timestamp`) AS max_timestamp FROM `moz-fx-data-shared-prod`.stripe_external.subscriptions_changelog_v1 GROUP BY subscription.id ) SELECT subscriptions_history.* FROM subscriptions_history LEFT JOIN latest_subscriptions_changelog USING (subscription_id) WHERE subscriptions_history._fivetran_start > latest_subscriptions_changelog.max_timestamp OR latest_subscriptions_changelog.max_timestamp IS NULL {% endif %} ), subscription_items AS ( SELECT id, created, PARSE_JSON(metadata) AS metadata, plan_id, quantity, subscription_id, FROM `moz-fx-data-shared-prod`.stripe_external.subscription_item_v1 QUALIFY -- With how SubPlat currently works each Stripe subscription should only have -- one subscription item, and we enforce that so the ETL can rely on it. 1 = COUNT(*) OVER (PARTITION BY subscription_id) ), products AS ( SELECT id, created, description, PARSE_JSON(metadata) AS metadata, name, statement_descriptor, updated, FROM `moz-fx-data-shared-prod`.stripe_external.product_v1 ), plans AS ( SELECT id, aggregate_usage, amount, billing_scheme, created, currency, `interval`, interval_count, PARSE_JSON(metadata) AS metadata, nickname, product_id, tiers_mode, trial_period_days, usage_type, FROM `moz-fx-data-shared-prod`.stripe_external.plan_v1 ), subscriptions_history_with_plan_metadata AS ( SELECT *, JSON_VALUE(metadata.previous_plan_id) AS previous_plan_id, LEAD(JSON_VALUE(metadata.previous_plan_id)) OVER ( PARTITION BY subscription_id ORDER BY _fivetran_start ) AS lead_previous_plan_id FROM new_subscriptions_history ), subscriptions_history_with_end_plan_ids AS ( -- Determine the plan ID for the last record in each time span that a subscription had a particular plan. SELECT subscriptions_history.*, CASE -- The latest history record gets the current plan from its associated subscription item. WHEN subscriptions_history._fivetran_active THEN subscription_items.plan_id -- A new `previous_plan_id` value means the previous record was the last record with that plan. WHEN subscriptions_history.lead_previous_plan_id IS DISTINCT FROM subscriptions_history.previous_plan_id THEN subscriptions_history.lead_previous_plan_id ELSE NULL END AS end_plan_id FROM subscriptions_history_with_plan_metadata AS subscriptions_history JOIN subscription_items ON subscriptions_history.subscription_id = subscription_items.subscription_id ), subscriptions_history_with_plan_ids AS ( -- Fill in `plan_id` by getting the next `end_plan_id`. SELECT *, FIRST_VALUE(end_plan_id IGNORE NULLS) OVER ( PARTITION BY subscription_id ORDER BY _fivetran_start ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS plan_id FROM subscriptions_history_with_end_plan_ids ), subscriptions_history_tax_rates AS ( SELECT subscriptions_history.id AS subscription_history_id, ARRAY_AGG( STRUCT( subscription_tax_rates.tax_rate_id AS id, tax_rates.created, tax_rates.description, tax_rates.display_name, tax_rates.inclusive, tax_rates.jurisdiction, PARSE_JSON(tax_rates.metadata) AS metadata, tax_rates.percentage ) ORDER BY tax_rates.created ) AS tax_rates FROM new_subscriptions_history AS subscriptions_history JOIN `moz-fx-data-shared-prod`.stripe_external.subscription_tax_rate_v1 AS subscription_tax_rates ON subscriptions_history.subscription_id = subscription_tax_rates.subscription_id JOIN `moz-fx-data-shared-prod`.stripe_external.tax_rate_v1 AS tax_rates ON subscription_tax_rates.tax_rate_id = tax_rates.id AND subscriptions_history._fivetran_start >= tax_rates.created GROUP BY subscriptions_history.id ), subscriptions_history_latest_discounts AS ( SELECT subscriptions_history.id AS subscription_history_id, ARRAY_AGG( STRUCT( subscription_discounts.id, STRUCT( subscription_discounts.coupon_id AS id, coupons.amount_off, coupons.created, coupons.currency, coupons.duration, coupons.duration_in_months, PARSE_JSON(coupons.metadata) AS metadata, coupons.name, coupons.percent_off, coupons.redeem_by ) AS coupon, subscription_discounts.`end`, subscription_discounts.invoice_id, subscription_discounts.invoice_item_id, subscription_discounts.promotion_code AS promotion_code_id, subscription_discounts.start ) ORDER BY subscription_discounts.start DESC LIMIT 1 )[SAFE_ORDINAL(1)] AS discount FROM new_subscriptions_history AS subscriptions_history JOIN `moz-fx-data-shared-prod`.stripe_external.subscription_discount_v2 AS subscription_discounts ON subscriptions_history.subscription_id = subscription_discounts.subscription_id AND subscriptions_history._fivetran_start >= subscription_discounts.start AND ( subscriptions_history._fivetran_start < subscription_discounts.`end` OR subscription_discounts.`end` IS NULL ) JOIN `moz-fx-data-shared-prod`.stripe_external.coupon_v1 AS coupons ON subscription_discounts.coupon_id = coupons.id GROUP BY subscriptions_history.id ) SELECT subscriptions_history.id, subscriptions_history._fivetran_start AS `timestamp`, subscriptions_history._fivetran_synced AS synced_at, STRUCT( subscriptions_history.subscription_id AS id, subscriptions_history.billing_cycle_anchor, subscriptions_history.cancel_at, subscriptions_history.cancel_at_period_end, subscriptions_history.canceled_at, subscriptions_history.collection_method, subscriptions_history.created, subscriptions_history.current_period_end, subscriptions_history.current_period_start, subscriptions_history.customer_id, subscriptions_history.days_until_due, subscriptions_history.default_payment_method_id, subscriptions_history.default_source_id, COALESCE(subscriptions_history_tax_rates.tax_rates, []) AS default_tax_rates, subscriptions_history_latest_discounts.discount, subscriptions_history.ended_at, -- While SubPlat currently only allows subscriptions to have a single item, -- they're planning to allow subscriptions with multiple items at some point. [ STRUCT( subscription_items.id, subscription_items.created, subscription_items.metadata, STRUCT( subscriptions_history.plan_id AS id, plans.aggregate_usage, plans.amount, plans.billing_scheme, plans.created, plans.currency, plans.`interval`, plans.interval_count, plans.metadata, plans.nickname, STRUCT( plans.product_id AS id, products.created, products.description, products.metadata, products.name, products.statement_descriptor, products.updated ) AS product, plans.tiers_mode, plans.trial_period_days, plans.usage_type ) AS plan, subscription_items.quantity ) ] AS items, subscriptions_history.latest_invoice_id, subscriptions_history.metadata, subscriptions_history.pending_setup_intent_id, subscriptions_history.start_date, subscriptions_history.status, subscriptions_history.trial_end, subscriptions_history.trial_start ) AS subscription FROM subscriptions_history_with_plan_ids AS subscriptions_history JOIN subscription_items ON subscriptions_history.subscription_id = subscription_items.subscription_id LEFT JOIN plans ON subscriptions_history.plan_id = plans.id LEFT JOIN products ON plans.product_id = products.id LEFT JOIN subscriptions_history_tax_rates ON subscriptions_history.id = subscriptions_history_tax_rates.subscription_history_id LEFT JOIN subscriptions_history_latest_discounts ON subscriptions_history.id = subscriptions_history_latest_discounts.subscription_history_id