diff --git a/posthog/hogql/database/schema/test/__snapshots__/test_groups_revenue_analytics.ambr b/posthog/hogql/database/schema/test/__snapshots__/test_groups_revenue_analytics.ambr index bb9cfab0edd5..3c6423ca6a5b 100644 --- a/posthog/hogql/database/schema/test/__snapshots__/test_groups_revenue_analytics.ambr +++ b/posthog/hogql/database/schema/test/__snapshots__/test_groups_revenue_analytics.ambr @@ -245,28 +245,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key @@ -658,28 +685,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key @@ -868,28 +922,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key @@ -1078,28 +1159,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key @@ -1288,28 +1396,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key @@ -1499,28 +1634,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key @@ -1921,28 +2083,55 @@ sum(coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)'))) AS revenue, sum(coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)'))) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT groups.key AS key, key AS revenue_analytics_customer__groups___key diff --git a/posthog/hogql/database/schema/test/__snapshots__/test_persons_revenue_analytics.ambr b/posthog/hogql/database/schema/test/__snapshots__/test_persons_revenue_analytics.ambr index 810297f6c04b..f6d8d11c1df0 100644 --- a/posthog/hogql/database/schema/test/__snapshots__/test_persons_revenue_analytics.ambr +++ b/posthog/hogql/database/schema/test/__snapshots__/test_persons_revenue_analytics.ambr @@ -202,209 +202,6 @@ use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_get_revenue_for_events_with_managed_viewsets_ff - ''' - SELECT persons__revenue_analytics.revenue AS revenue, - persons__revenue_analytics.revenue AS `$virt_revenue` - FROM - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, - person.id AS id - FROM person - WHERE and(equals(person.team_id, 99999), in(id, - (SELECT where_optimization.id AS id - FROM person AS where_optimization - WHERE and(equals(where_optimization.team_id, 99999), equals(where_optimization.id, '00000000-0000-0000-0000-000000000000'))))) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))) AS persons - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events__person.id AS person_id - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - INNER JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons__revenue_analytics ON equals(toString(persons.persons___id), toString(persons__revenue_analytics.person_id)) - WHERE ifNull(equals(persons.id, '00000000-0000-0000-0000-000000000000'), 0) - LIMIT 100 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- # name: TestPersonsRevenueAnalytics.test_get_revenue_for_schema_source_for_customer_with_multiple_distinct_ids ''' SELECT persons.id AS id, @@ -422,28 +219,55 @@ coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -635,28 +459,55 @@ coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -850,28 +701,55 @@ coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -1064,28 +942,55 @@ coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -1278,28 +1183,55 @@ coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -1475,10 +1407,11 @@ use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_get_revenue_for_schema_source_for_id_join_with_managed_viewsets_ff +# name: TestPersonsRevenueAnalytics.test_get_revenue_for_schema_source_for_metadata_join ''' SELECT persons.id AS id, - persons__revenue_analytics.revenue AS revenue + persons__revenue_analytics.revenue AS revenue, + persons__revenue_analytics.revenue AS `$virt_revenue` FROM (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, person.id AS id @@ -1492,28 +1425,55 @@ coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -1524,13 +1484,13 @@ WHERE equals(person.team_id, 99999) GROUP BY person.id HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN + LEFT JOIN (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id FROM person_distinct_id2 WHERE equals(person_distinct_id2.team_id, 99999) GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS persons__pdi ON equals(persons.persons___id, persons__pdi.person_id)) AS revenue_analytics_customer__persons ON equals(revenue_analytics_customer.id, revenue_analytics_customer__persons.revenue_analytics_customer__persons___pdi___distinct_id) + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS persons__pdi ON equals(persons.persons___id, persons__pdi.person_id)) AS revenue_analytics_customer__persons ON equals(JSONExtractString(revenue_analytics_customer.metadata, 'id'), revenue_analytics_customer__persons.revenue_analytics_customer__persons___pdi___distinct_id) LEFT JOIN (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, sum(revenue_analytics_revenue_item.amount) AS revenue @@ -1645,7 +1605,7 @@ ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) + WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) GROUP BY revenue_item.source_label, revenue_item.customer_id, revenue_item.subscription_id, timestamp @@ -1666,7 +1626,7 @@ toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, '' AS metadata WHERE 0) AS `stripe.posthog_test.subscription_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) + WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) ORDER BY timestamp DESC) AS union GROUP BY source_label, @@ -1689,45 +1649,285 @@ use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_get_revenue_for_schema_source_for_id_join_with_managed_viewsets_ff.1 +# name: TestPersonsRevenueAnalytics.test_query_revenue_analytics_table_events ''' - SELECT persons.id AS id, - persons__revenue_analytics.revenue AS `$virt_revenue` - FROM - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - LEFT JOIN + SELECT persons_revenue_analytics.person_id AS person_id, + persons_revenue_analytics.revenue AS revenue, + persons_revenue_analytics.mrr AS mrr + FROM (SELECT 99999 AS team_id, - revenue_analytics_customer__persons.id AS person_id, + revenue_analytics_customer.id AS person_id, coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT toString(persons.id) AS id, + 'revenue_analytics.events.purchase' AS source_label, + persons.created_at AS timestamp, + persons.properties___name AS name, + persons.properties___email AS email, + persons.properties___phone AS phone, + persons.properties___address AS address, + persons.properties___metadata AS metadata, + persons.`properties___$geoip_country_name` AS country, + formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, + NULL AS initial_coupon, + NULL AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer + (SELECT person.id AS id, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, + toTimeZone(person.created_at, 'UTC') AS created_at + FROM person + WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), + (SELECT person.id AS id, max(person.version) AS version + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons + INNER JOIN + (SELECT DISTINCT events__person.id AS person_id + FROM events + LEFT OUTER JOIN + (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + LEFT JOIN + (SELECT person.id AS id + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) + WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) + ORDER BY persons.created_at DESC) AS revenue_analytics_customer + LEFT JOIN + (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, + sum(revenue_analytics_revenue_item.amount) AS revenue + FROM + (SELECT toString(events.uuid) AS id, + toString(events.uuid) AS invoice_item_id, + 'revenue_analytics.events.purchase' AS source_label, + toTimeZone(events.timestamp, 'UTC') AS timestamp, + timestamp AS created_at, + isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '')) AS is_recurring, + NULL AS product_id, + toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, + events.`$group_0` AS group_0_key, + events.`$group_1` AS group_1_key, + events.`$group_2` AS group_2_key, + events.`$group_3` AS group_3_key, + events.`$group_4` AS group_4_key, + NULL AS invoice_id, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, + toString(events.`$session_id`) AS session_id, + events.event AS event_name, + NULL AS coupon, + coupon AS coupon_id, + 'USD' AS original_currency, + accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, + in(original_currency, + ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, + if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, + divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, + 'USD' AS currency, + if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + LEFT OUTER JOIN + (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_analytics_revenue_item + GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) + LEFT JOIN + (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, + sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr + FROM + (SELECT union.source_label AS source_label, + union.customer_id AS customer_id, + union.subscription_id AS subscription_id, + argMax(union.amount, union.timestamp) AS mrr + FROM + (SELECT revenue_item.source_label AS source_label, + revenue_item.customer_id AS customer_id, + revenue_item.subscription_id AS subscription_id, + toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, + sum(revenue_item.amount) AS amount + FROM + (SELECT toString(events.uuid) AS id, + toString(events.uuid) AS invoice_item_id, + 'revenue_analytics.events.purchase' AS source_label, + toTimeZone(events.timestamp, 'UTC') AS timestamp, + timestamp AS created_at, + isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '')) AS is_recurring, + NULL AS product_id, + toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, + events.`$group_0` AS group_0_key, + events.`$group_1` AS group_1_key, + events.`$group_2` AS group_2_key, + events.`$group_3` AS group_3_key, + events.`$group_4` AS group_4_key, + NULL AS invoice_id, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, + toString(events.`$session_id`) AS session_id, + events.event AS event_name, + NULL AS coupon, + coupon AS coupon_id, + 'USD' AS original_currency, + accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, + in(original_currency, + ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, + if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, + divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, + 'USD' AS currency, + if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + LEFT OUTER JOIN + (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_item + WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) + GROUP BY revenue_item.source_label, + revenue_item.customer_id, + revenue_item.subscription_id, timestamp + ORDER BY timestamp DESC + UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, + `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, + `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, + toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, + accurateCastOrNull(0, 'Decimal64(10)') AS amount + FROM + (SELECT subscription_id AS id, + 'revenue_analytics.events.purchase' AS source_label, + NULL AS plan_id, + product_id AS product_id, + toString(person_id) AS customer_id, + NULL AS status, + min_timestamp AS started_at, + if(ifNull(greater(max_timestamp_plus_dropoff_days, today()), 0), NULL, max_timestamp_plus_dropoff_days) AS ended_at, + NULL AS metadata + FROM + (SELECT events__person.id AS person_id, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, + NULL AS product_id, + min(toTimeZone(events.timestamp, 'UTC')) AS min_timestamp, + max(toTimeZone(events.timestamp, 'UTC')) AS max_timestamp, + addDays(max_timestamp, 45.0) AS max_timestamp_plus_dropoff_days + FROM events + LEFT OUTER JOIN + (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + LEFT JOIN + (SELECT person.id AS id + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) + WHERE and(equals(events.team_id, 99999), and(1, isNotNull(subscription_id))) + GROUP BY subscription_id, + person_id) + ORDER BY started_at DESC) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` + WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) + ORDER BY timestamp DESC) AS + union + GROUP BY source_label, + customer_id, + subscription_id + ORDER BY customer_id ASC, + subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` + GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons_revenue_analytics + ORDER BY persons_revenue_analytics.person_id ASC + LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, + readonly=2, + max_execution_time=60, + allow_experimental_object_type=1, + max_ast_elements=4000000, + max_expanded_ast_elements=4000000, + max_bytes_before_external_group_by=0, + transform_null_in=1, + optimize_min_equality_disjunction_chain_length=4294967295, + allow_experimental_join_condition=1, + use_hive_partitioning=0 + ''' +# --- +# name: TestPersonsRevenueAnalytics.test_query_revenue_analytics_table_sources + ''' + SELECT persons_revenue_analytics.person_id AS person_id, + persons_revenue_analytics.revenue AS revenue, + persons_revenue_analytics.mrr AS mrr + FROM + (SELECT 99999 AS team_id, + revenue_analytics_customer__persons.id AS person_id, + coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, + coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr + FROM + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer LEFT JOIN (SELECT persons.id AS id, persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id @@ -1738,7 +1938,7 @@ WHERE equals(person.team_id, 99999) GROUP BY person.id HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN + LEFT JOIN (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id FROM person_distinct_id2 @@ -1859,7 +2059,7 @@ ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) + WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) GROUP BY revenue_item.source_label, revenue_item.customer_id, revenue_item.subscription_id, timestamp @@ -1880,7 +2080,7 @@ toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, '' AS metadata WHERE 0) AS `stripe.posthog_test.subscription_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) + WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) ORDER BY timestamp DESC) AS union GROUP BY source_label, @@ -1888,8 +2088,9 @@ subscription_id ORDER BY customer_id ASC, subscription_id ASC) AS `stripe.posthog_test.mrr_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons__revenue_analytics ON equals(toString(persons.persons___id), toString(persons__revenue_analytics.person_id)) - ORDER BY persons.id ASC + GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons_revenue_analytics + ORDER BY persons_revenue_analytics.mrr DESC, + persons_revenue_analytics.revenue DESC LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, readonly=2, max_execution_time=60, @@ -1903,3084 +2104,731 @@ use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_get_revenue_for_schema_source_for_metadata_join +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_0_disabled ''' - SELECT persons.id AS id, - persons__revenue_analytics.revenue AS revenue, - persons__revenue_analytics.revenue AS `$virt_revenue` - FROM - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer__persons.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer - LEFT JOIN - (SELECT persons.id AS id, - persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id - FROM - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - LEFT JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS persons__pdi ON equals(persons.persons___id, persons__pdi.person_id)) AS revenue_analytics_customer__persons ON equals(JSONExtractString(revenue_analytics_customer.metadata, 'id'), revenue_analytics_customer__persons.revenue_analytics_customer__persons___pdi___distinct_id) - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, - JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount - FROM - (SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, - JSONExtractString(data, 'id') AS invoice_item_id, - JSONExtractUInt(data, 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, - JSONExtractString(data, 'currency') AS currency, - JSONExtractString(data, 'price', 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, period_months)) AS month_index, - ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice - WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `stripe.posthog_test.mrr_revenue_view`.customer_id AS customer_id, - sum(`stripe.posthog_test.mrr_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, - JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount - FROM - (SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, - JSONExtractString(data, 'id') AS invoice_item_id, - JSONExtractUInt(data, 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, - JSONExtractString(data, 'currency') AS currency, - JSONExtractString(data, 'price', 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, period_months)) AS month_index, - ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice - WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `stripe.posthog_test.subscription_revenue_view`.source_label AS source_label, - `stripe.posthog_test.subscription_revenue_view`.customer_id AS customer_id, - `stripe.posthog_test.subscription_revenue_view`.id AS subscription_id, - toTimeZone(`stripe.posthog_test.subscription_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `stripe.posthog_test.subscription_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `stripe.posthog_test.mrr_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons__revenue_analytics ON equals(toString(persons.persons___id), toString(persons__revenue_analytics.person_id)) - ORDER BY persons.id ASC - LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, - readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 + SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp + FROM events + WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) + ORDER BY toTimeZone(events.timestamp, 'UTC') ASC + LIMIT 1 SETTINGS readonly=2, + max_execution_time=60, + allow_experimental_object_type=1, + max_ast_elements=4000000, + max_expanded_ast_elements=4000000, + max_bytes_before_external_group_by=0, + transform_null_in=1, + optimize_min_equality_disjunction_chain_length=4294967295, + allow_experimental_join_condition=1, + use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_query_revenue_analytics_table_events +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_0_disabled.1 ''' - SELECT persons_revenue_analytics.person_id AS person_id, - persons_revenue_analytics.revenue AS revenue, - persons_revenue_analytics.mrr AS mrr - FROM - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events__person.id AS person_id - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - LEFT JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '')) AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr + SELECT groupArray(1)(date)[1] AS date, arrayFold((acc, x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, plus(length(date), 1))), groupArray(ifNull(total, 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, 25), 0), 0), '$$_posthog_breakdown_other_$$', i), breakdown_value) AS breakdown_value + FROM ( + SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, 0)), indexOf(groupArray(day_start) AS _days_for_count, _match_date) AS _index, plus(minus(arrayLastIndex(x -> ifNull(equals(x, _match_date), isNull(x) + and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, breakdown_value AS breakdown_value, rowNumberInAllBlocks() AS row_number + FROM ( + SELECT sum(total) AS count, day_start AS day_start, [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value + FROM ( + SELECT count() AS total, toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, ifNull(nullIf(leftUTF8(toString(e__pdi__person__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 + FROM events AS e + INNER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS e__pdi___person_id, tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id + FROM person_distinct_id2 + WHERE equals(person_distinct_id2.team_id, 99999) + GROUP BY person_distinct_id2.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id) + LEFT JOIN ( + SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS e__pdi__person___id, person.id AS id + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__pdi__person ON equals(e__pdi.e__pdi___person_id, e__pdi__person.e__pdi__person___id) + LEFT JOIN ( + SELECT 99999 AS team_id, revenue_analytics_customer.id AS person_id, coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr + FROM ( + SELECT toString(persons.id) AS id, 'revenue_analytics.events.purchase' AS source_label, persons.created_at AS timestamp, persons.properties___name AS name, persons.properties___email AS email, persons.properties___phone AS phone, persons.properties___address AS address, persons.properties___metadata AS metadata, persons.`properties___$geoip_country_name` AS country, formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, NULL AS initial_coupon, NULL AS initial_coupon_id + FROM ( + SELECT person.id AS id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, toTimeZone(person.created_at, 'UTC') AS created_at + FROM person + WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), ( + SELECT person.id AS id, max(person.version) AS version + FROM person WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons + INNER JOIN ( + SELECT DISTINCT events__pdi__person.id AS person_id + FROM events + INNER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS events__pdi___person_id, tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id + FROM person_distinct_id2 + WHERE equals(person_distinct_id2.team_id, 99999) + GROUP BY person_distinct_id2.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) + LEFT JOIN ( + SELECT person.id AS id + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__pdi__person ON equals(events__pdi.events__pdi___person_id, events__pdi__person.id) + WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) + ORDER BY persons.created_at DESC) AS revenue_analytics_customer + LEFT JOIN ( + SELECT revenue_analytics_revenue_item.customer_id AS customer_id, sum(revenue_analytics_revenue_item.amount) AS revenue + FROM ( + SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(events__pdi.person_id) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + INNER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id + FROM person_distinct_id2 + WHERE equals(person_distinct_id2.team_id, 99999) + GROUP BY person_distinct_id2.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_analytics_revenue_item + GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) + LEFT JOIN ( + SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr + FROM ( + SELECT union.source_label AS source_label, union.customer_id AS customer_id, union.subscription_id AS subscription_id, argMax(union.amount, union.timestamp) AS mrr + FROM ( + SELECT revenue_item.source_label AS source_label, revenue_item.customer_id AS customer_id, revenue_item.subscription_id AS subscription_id, toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, sum(revenue_item.amount) AS amount + FROM ( + SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(events__pdi.person_id) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + INNER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id + FROM person_distinct_id2 + WHERE equals(person_distinct_id2.team_id, 99999) + GROUP BY person_distinct_id2.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_item + WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) + GROUP BY revenue_item.source_label, revenue_item.customer_id, revenue_item.subscription_id, timestamp + ORDER BY timestamp DESC + UNION ALL + SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, accurateCastOrNull(0, 'Decimal64(10)') AS amount + FROM ( + SELECT '' AS id, '' AS source_label, '' AS plan_id, '' AS product_id, '' AS customer_id, '' AS status, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, '' AS metadata + WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) + ORDER BY timestamp DESC) AS + union + GROUP BY source_label, customer_id, subscription_id + ORDER BY customer_id ASC, subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` + GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__pdi__person__revenue_analytics ON equals(toString(e__pdi__person.e__pdi__person___id), toString(e__pdi__person__revenue_analytics.person_id)) + WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) + GROUP BY day_start, breakdown_value_1) + GROUP BY day_start, breakdown_value_1 + ORDER BY day_start ASC, breakdown_value ASC) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC) + WHERE arrayExists(x -> isNotNull(x), breakdown_value) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC + LIMIT 50000 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0, transform_null_in=1, optimize_min_equality_disjunction_chain_length=4294967295, allow_experimental_join_condition=1, use_hive_partitioning=0 + ''' +# --- +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_1_person_id_no_override_properties_on_events + ''' + SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp + FROM events + WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) + ORDER BY toTimeZone(events.timestamp, 'UTC') ASC + LIMIT 1 SETTINGS readonly=2, + max_execution_time=60, + allow_experimental_object_type=1, + max_ast_elements=4000000, + max_expanded_ast_elements=4000000, + max_bytes_before_external_group_by=0, + transform_null_in=1, + optimize_min_equality_disjunction_chain_length=4294967295, + allow_experimental_join_condition=1, + use_hive_partitioning=0 + ''' +# --- +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_1_person_id_no_override_properties_on_events.1 + ''' + SELECT groupArray(1)(date)[1] AS date, + arrayFold((acc, x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, plus(length(date), 1))), groupArray(ifNull(total, 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, + arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, 25), 0), 0), '$$_posthog_breakdown_other_$$', i), breakdown_value) AS breakdown_value + FROM + (SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, + arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, 0)), indexOf(groupArray(day_start) AS _days_for_count, _match_date) AS _index, plus(minus(arrayLastIndex(x -> ifNull(equals(x, _match_date), isNull(x) + and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, + breakdown_value AS breakdown_value, + rowNumberInAllBlocks() AS row_number + FROM + (SELECT sum(total) AS count, + day_start AS day_start, + [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '')) AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount + (SELECT count() AS total, + toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, + ifNull(nullIf(leftUTF8(toString(e__poe__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 + FROM events AS e + LEFT JOIN + (SELECT 99999 AS team_id, + revenue_analytics_customer.id AS person_id, + coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, + coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr FROM - (SELECT subscription_id AS id, + (SELECT toString(persons.id) AS id, 'revenue_analytics.events.purchase' AS source_label, - NULL AS plan_id, - product_id AS product_id, - toString(person_id) AS customer_id, - NULL AS status, - min_timestamp AS started_at, - if(ifNull(greater(max_timestamp_plus_dropoff_days, today()), 0), NULL, max_timestamp_plus_dropoff_days) AS ended_at, - NULL AS metadata + persons.created_at AS timestamp, + persons.properties___name AS name, + persons.properties___email AS email, + persons.properties___phone AS phone, + persons.properties___address AS address, + persons.properties___metadata AS metadata, + persons.`properties___$geoip_country_name` AS country, + formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, + NULL AS initial_coupon, + NULL AS initial_coupon_id FROM - (SELECT events__person.id AS person_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, + (SELECT person.id AS id, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, + toTimeZone(person.created_at, 'UTC') AS created_at + FROM person + WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), + (SELECT person.id AS id, max(person.version) AS version + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons + INNER JOIN + (SELECT DISTINCT events.person_id AS person_id + FROM events + WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) + ORDER BY persons.created_at DESC) AS revenue_analytics_customer + LEFT JOIN + (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, + sum(revenue_analytics_revenue_item.amount) AS revenue + FROM + (SELECT toString(events.uuid) AS id, + toString(events.uuid) AS invoice_item_id, + 'revenue_analytics.events.purchase' AS source_label, + toTimeZone(events.timestamp, 'UTC') AS timestamp, + timestamp AS created_at, + 0 AS is_recurring, NULL AS product_id, - min(toTimeZone(events.timestamp, 'UTC')) AS min_timestamp, - max(toTimeZone(events.timestamp, 'UTC')) AS max_timestamp, - addDays(max_timestamp, 45.0) AS max_timestamp_plus_dropoff_days + toString(events.person_id) AS customer_id, + events.`$group_0` AS group_0_key, + events.`$group_1` AS group_1_key, + events.`$group_2` AS group_2_key, + events.`$group_3` AS group_3_key, + events.`$group_4` AS group_4_key, + NULL AS invoice_id, + NULL AS subscription_id, + toString(events.`$session_id`) AS session_id, + events.event AS event_name, + NULL AS coupon, + coupon AS coupon_id, + 'USD' AS original_currency, + accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, + in(original_currency, + ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, + if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, + divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, + 'USD' AS currency, + if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - LEFT JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE and(equals(events.team_id, 99999), and(1, isNotNull(subscription_id))) - GROUP BY subscription_id, - person_id) - ORDER BY started_at DESC) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons_revenue_analytics - ORDER BY persons_revenue_analytics.person_id ASC - LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, - readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_analytics_revenue_item + GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) + LEFT JOIN + (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, + sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr + FROM + (SELECT union.source_label AS source_label, + union.customer_id AS customer_id, + union.subscription_id AS subscription_id, + argMax(union.amount, union.timestamp) AS mrr + FROM + (SELECT revenue_item.source_label AS source_label, + revenue_item.customer_id AS customer_id, + revenue_item.subscription_id AS subscription_id, + toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, + sum(revenue_item.amount) AS amount + FROM + (SELECT toString(events.uuid) AS id, + toString(events.uuid) AS invoice_item_id, + 'revenue_analytics.events.purchase' AS source_label, + toTimeZone(events.timestamp, 'UTC') AS timestamp, + timestamp AS created_at, + 0 AS is_recurring, + NULL AS product_id, + toString(events.person_id) AS customer_id, + events.`$group_0` AS group_0_key, + events.`$group_1` AS group_1_key, + events.`$group_2` AS group_2_key, + events.`$group_3` AS group_3_key, + events.`$group_4` AS group_4_key, + NULL AS invoice_id, + NULL AS subscription_id, + toString(events.`$session_id`) AS session_id, + events.event AS event_name, + NULL AS coupon, + coupon AS coupon_id, + 'USD' AS original_currency, + accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, + in(original_currency, + ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, + if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, + divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, + 'USD' AS currency, + if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_item + WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) + GROUP BY revenue_item.source_label, + revenue_item.customer_id, + revenue_item.subscription_id, timestamp + ORDER BY timestamp DESC + UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, + `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, + `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, + toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, + accurateCastOrNull(0, 'Decimal64(10)') AS amount + FROM + (SELECT '' AS id, + '' AS source_label, + '' AS plan_id, + '' AS product_id, + '' AS customer_id, + '' AS status, + toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, + toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, + '' AS metadata + WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` + WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) + ORDER BY timestamp DESC) AS + union + GROUP BY source_label, + customer_id, + subscription_id + ORDER BY customer_id ASC, + subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` + GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__poe__revenue_analytics ON equals(toString(e.person_id), toString(e__poe__revenue_analytics.person_id)) + WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) + GROUP BY day_start, + breakdown_value_1) + GROUP BY day_start, + breakdown_value_1 + ORDER BY day_start ASC, + breakdown_value ASC) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC) + WHERE arrayExists(x -> isNotNull(x), breakdown_value) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC + LIMIT 50000 SETTINGS readonly=2, + max_execution_time=60, + allow_experimental_object_type=1, + max_ast_elements=4000000, + max_expanded_ast_elements=4000000, + max_bytes_before_external_group_by=0, + transform_null_in=1, + optimize_min_equality_disjunction_chain_length=4294967295, + allow_experimental_join_condition=1, + use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_query_revenue_analytics_table_events_with_managed_viewsets_ff +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_2_person_id_override_properties_on_events ''' - SELECT persons_revenue_analytics.person_id AS person_id, - persons_revenue_analytics.revenue AS revenue, - persons_revenue_analytics.mrr AS mrr - FROM - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events__person.id AS person_id - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - INNER JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '')) AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '')) AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT subscription_id AS id, - 'revenue_analytics.events.purchase' AS source_label, - NULL AS plan_id, - product_id AS product_id, - toString(person_id) AS customer_id, - NULL AS status, - min_timestamp AS started_at, - if(ifNull(greater(max_timestamp_plus_dropoff_days, today()), 0), NULL, max_timestamp_plus_dropoff_days) AS ended_at, - NULL AS metadata - FROM - (SELECT events__person.id AS person_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription_id'), ''), 'null'), '^"|"$', '') AS subscription_id, - NULL AS product_id, - min(toTimeZone(events.timestamp, 'UTC')) AS min_timestamp, - max(toTimeZone(events.timestamp, 'UTC')) AS max_timestamp, - addDays(max_timestamp, 45.0) AS max_timestamp_plus_dropoff_days - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - INNER JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE and(equals(events.team_id, 99999), and(1, isNotNull(subscription_id))) - GROUP BY subscription_id, - person_id) - ORDER BY started_at DESC) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons_revenue_analytics - ORDER BY persons_revenue_analytics.person_id ASC - LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, - readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 + SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp + FROM events + WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) + ORDER BY toTimeZone(events.timestamp, 'UTC') ASC + LIMIT 1 SETTINGS readonly=2, + max_execution_time=60, + allow_experimental_object_type=1, + max_ast_elements=4000000, + max_expanded_ast_elements=4000000, + max_bytes_before_external_group_by=0, + transform_null_in=1, + optimize_min_equality_disjunction_chain_length=4294967295, + allow_experimental_join_condition=1, + use_hive_partitioning=0 ''' # --- -# name: TestPersonsRevenueAnalytics.test_query_revenue_analytics_table_sources +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_2_person_id_override_properties_on_events.1 ''' - SELECT persons_revenue_analytics.person_id AS person_id, - persons_revenue_analytics.revenue AS revenue, - persons_revenue_analytics.mrr AS mrr - FROM - (SELECT 99999 AS team_id, - revenue_analytics_customer__persons.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer - LEFT JOIN - (SELECT persons.id AS id, - persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id - FROM - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - LEFT JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS persons__pdi ON equals(persons.persons___id, persons__pdi.person_id)) AS revenue_analytics_customer__persons ON equals(revenue_analytics_customer.id, revenue_analytics_customer__persons.revenue_analytics_customer__persons___pdi___distinct_id) - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, - JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount - FROM - (SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, - JSONExtractString(data, 'id') AS invoice_item_id, - JSONExtractUInt(data, 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, - JSONExtractString(data, 'currency') AS currency, - JSONExtractString(data, 'price', 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, period_months)) AS month_index, - ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice - WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `stripe.posthog_test.mrr_revenue_view`.customer_id AS customer_id, - sum(`stripe.posthog_test.mrr_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, - JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount - FROM - (SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, - JSONExtractString(data, 'id') AS invoice_item_id, - JSONExtractUInt(data, 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, - JSONExtractString(data, 'currency') AS currency, - JSONExtractString(data, 'price', 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, period_months)) AS month_index, - ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice - WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `stripe.posthog_test.subscription_revenue_view`.source_label AS source_label, - `stripe.posthog_test.subscription_revenue_view`.customer_id AS customer_id, - `stripe.posthog_test.subscription_revenue_view`.id AS subscription_id, - toTimeZone(`stripe.posthog_test.subscription_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `stripe.posthog_test.subscription_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `stripe.posthog_test.mrr_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons_revenue_analytics - ORDER BY persons_revenue_analytics.mrr DESC, - persons_revenue_analytics.revenue DESC - LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, - readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_query_revenue_analytics_table_sources_with_managed_viewsets_ff - ''' - SELECT persons_revenue_analytics.person_id AS person_id, - persons_revenue_analytics.revenue AS revenue, - persons_revenue_analytics.mrr AS mrr - FROM - (SELECT 99999 AS team_id, - revenue_analytics_customer__persons.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id - FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer - LEFT JOIN - (SELECT persons.id AS id, - persons__pdi.distinct_id AS revenue_analytics_customer__persons___pdi___distinct_id - FROM - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS persons___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS persons__pdi ON equals(persons.persons___id, persons__pdi.person_id)) AS revenue_analytics_customer__persons ON equals(revenue_analytics_customer.id, revenue_analytics_customer__persons.revenue_analytics_customer__persons___pdi___distinct_id) - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, - JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount - FROM - (SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, - JSONExtractString(data, 'id') AS invoice_item_id, - JSONExtractUInt(data, 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, - JSONExtractString(data, 'currency') AS currency, - JSONExtractString(data, 'price', 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, period_months)) AS month_index, - ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice - WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `stripe.posthog_test.mrr_revenue_view`.customer_id AS customer_id, - sum(`stripe.posthog_test.mrr_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, - JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount - FROM - (SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, - JSONExtractString(data, 'id') AS invoice_item_id, - JSONExtractUInt(data, 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, - JSONExtractString(data, 'currency') AS currency, - JSONExtractString(data, 'price', 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, period_months)) AS month_index, - ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice - WHERE posthog_test_stripe_invoice.paid) AS invoice) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `stripe.posthog_test.subscription_revenue_view`.source_label AS source_label, - `stripe.posthog_test.subscription_revenue_view`.customer_id AS customer_id, - `stripe.posthog_test.subscription_revenue_view`.id AS subscription_id, - toTimeZone(`stripe.posthog_test.subscription_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `stripe.posthog_test.subscription_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `stripe.posthog_test.mrr_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS persons_revenue_analytics - ORDER BY persons_revenue_analytics.mrr DESC, - persons_revenue_analytics.revenue DESC - LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, - readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_0_disabled - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_0_disabled.1 - ''' - SELECT groupArray(1)(date)[1] AS date, arrayFold((acc, x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, plus(length(date), 1))), groupArray(ifNull(total, 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, 25), 0), 0), '$$_posthog_breakdown_other_$$', i), breakdown_value) AS breakdown_value - FROM ( - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, 0)), indexOf(groupArray(day_start) AS _days_for_count, _match_date) AS _index, plus(minus(arrayLastIndex(x -> ifNull(equals(x, _match_date), isNull(x) - and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, breakdown_value AS breakdown_value, rowNumberInAllBlocks() AS row_number - FROM ( - SELECT sum(total) AS count, day_start AS day_start, [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM ( - SELECT count() AS total, toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, ifNull(nullIf(leftUTF8(toString(e__pdi__person__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - INNER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS e__pdi___person_id, tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id) - LEFT JOIN ( - SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS e__pdi__person___id, person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__pdi__person ON equals(e__pdi.e__pdi___person_id, e__pdi__person.e__pdi__person___id) - LEFT JOIN ( - SELECT 99999 AS team_id, revenue_analytics_customer.id AS person_id, coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM ( - SELECT toString(persons.id) AS id, 'revenue_analytics.events.purchase' AS source_label, persons.created_at AS timestamp, persons.properties___name AS name, persons.properties___email AS email, persons.properties___phone AS phone, persons.properties___address AS address, persons.properties___metadata AS metadata, persons.`properties___$geoip_country_name` AS country, formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, NULL AS initial_coupon, NULL AS initial_coupon_id - FROM ( - SELECT person.id AS id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), ( - SELECT person.id AS id, max(person.version) AS version - FROM person WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN ( - SELECT DISTINCT events__pdi__person.id AS person_id - FROM events - INNER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS events__pdi___person_id, tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) - LEFT JOIN ( - SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__pdi__person ON equals(events__pdi.events__pdi___person_id, events__pdi__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN ( - SELECT revenue_analytics_revenue_item.customer_id AS customer_id, sum(revenue_analytics_revenue_item.amount) AS revenue - FROM ( - SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(events__pdi.person_id) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - INNER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN ( - SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM ( - SELECT union.source_label AS source_label, union.customer_id AS customer_id, union.subscription_id AS subscription_id, argMax(union.amount, union.timestamp) AS mrr - FROM ( - SELECT revenue_item.source_label AS source_label, revenue_item.customer_id AS customer_id, revenue_item.subscription_id AS subscription_id, toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, sum(revenue_item.amount) AS amount - FROM ( - SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(events__pdi.person_id) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - INNER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - GROUP BY revenue_item.source_label, revenue_item.customer_id, revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL - SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM ( - SELECT '' AS id, '' AS source_label, '' AS plan_id, '' AS product_id, '' AS customer_id, '' AS status, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, customer_id, subscription_id - ORDER BY customer_id ASC, subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__pdi__person__revenue_analytics ON equals(toString(e__pdi__person.e__pdi__person___id), toString(e__pdi__person__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, breakdown_value_1) - GROUP BY day_start, breakdown_value_1 - ORDER BY day_start ASC, breakdown_value ASC) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC) - WHERE arrayExists(x -> isNotNull(x), breakdown_value) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0, transform_null_in=1, optimize_min_equality_disjunction_chain_length=4294967295, allow_experimental_join_condition=1, use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_1_person_id_no_override_properties_on_events - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_1_person_id_no_override_properties_on_events.1 - ''' - SELECT groupArray(1)(date)[1] AS date, - arrayFold((acc, x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, plus(length(date), 1))), groupArray(ifNull(total, 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, - arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, 25), 0), 0), '$$_posthog_breakdown_other_$$', i), breakdown_value) AS breakdown_value - FROM - (SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, - arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, 0)), indexOf(groupArray(day_start) AS _days_for_count, _match_date) AS _index, plus(minus(arrayLastIndex(x -> ifNull(equals(x, _match_date), isNull(x) - and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, - breakdown_value AS breakdown_value, - rowNumberInAllBlocks() AS row_number - FROM - (SELECT sum(total) AS count, - day_start AS day_start, - [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM - (SELECT count() AS total, - toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, - ifNull(nullIf(leftUTF8(toString(e__poe__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events.person_id AS person_id - FROM events - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(events.person_id) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(events.person_id) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('2025-05-30 00:00:00.000000', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__poe__revenue_analytics ON equals(toString(e.person_id), toString(e__poe__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, - breakdown_value_1) - GROUP BY day_start, - breakdown_value_1 - ORDER BY day_start ASC, - breakdown_value ASC) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC) - WHERE arrayExists(x -> isNotNull(x), breakdown_value) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_2_person_id_override_properties_on_events - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_2_person_id_override_properties_on_events.1 - ''' - SELECT groupArray(1)(date)[1] AS date, - arrayFold((acc, - x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, - plus(length(date), 1))), groupArray(ifNull(total, - 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, - arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, - 25), 0), 0), '$$_posthog_breakdown_other_$$', - i), breakdown_value) AS breakdown_value - FROM ( - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', - 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, - plus(coalesce(dateDiff('day', - toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', - 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', - 'UTC')), toIntervalDay(1)))), 1))) AS date, - arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, - 0)), indexOf(groupArray(day_start) AS _days_for_count, - _match_date) AS _index, - plus(minus(arrayLastIndex(x -> ifNull(equals(x, - _match_date), isNull(x) - and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, - breakdown_value AS breakdown_value, - rowNumberInAllBlocks() AS row_number - FROM ( - SELECT sum(total) AS count, - day_start AS day_start, - [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM ( - SELECT count() AS total, - toStartOfDay(toTimeZone(e.timestamp, - 'UTC')) AS day_start, - ifNull(nullIf(leftUTF8(toString(e__poe__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__override ON equals(e.distinct_id, - e__override.distinct_id) - LEFT JOIN ( - SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, - accurateCastOrNull(0, - 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, - accurateCastOrNull(0, - 'Decimal64(10)')) AS mrr - FROM ( - SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM ( - SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'name'), ''), 'null'), '^"|"$', - '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'email'), ''), 'null'), '^"|"$', - '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'phone'), ''), 'null'), '^"|"$', - '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'address'), ''), 'null'), '^"|"$', - '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'metadata'), ''), 'null'), '^"|"$', - '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - '$geoip_country_name'), ''), 'null'), '^"|"$', - '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, - 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, - 99999), in(tuple(person.id, - person.version), ( - SELECT person.id AS id, - max(person.version) AS version - FROM person WHERE equals(person.team_id, - 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, - person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, - 'UTC'), person.version), plus(now64(6, - 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN ( - SELECT DISTINCT if(not(empty(events__override.distinct_id)), events__override.person_id, - events.person_id) AS person_id - FROM events - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, - events__override.distinct_id) - WHERE equals(events.team_id, - 99999)) AS events ON equals(persons.id, - events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN ( - SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM ( - SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, - 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, - events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'revenue'), ''), 'null'), '^"|"$', - ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, - accurateCastOrNull(1, - 'Decimal64(10)'), accurateCastOrNull(100, - 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, - currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, - 'Decimal64(10)'), if(equals('USD', - 'USD'), toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)) = 0, - toDecimal64(0, - 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)) = 0, - toDecimal64(1, - 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)))))) AS amount - FROM events - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, - events__override.distinct_id) - WHERE and(equals(events.team_id, - 99999), and(equals(events.event, - 'purchase'), 1, - isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, - revenue_agg.customer_id) - LEFT JOIN ( - SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM ( - SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, - union.timestamp) AS mrr - FROM ( - SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, - 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM ( - SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, - 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, - events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'revenue'), ''), 'null'), '^"|"$', - ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, - accurateCastOrNull(1, - 'Decimal64(10)'), accurateCastOrNull(100, - 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, - currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, - 'Decimal64(10)'), if(equals('USD', - 'USD'), toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)) = 0, - toDecimal64(0, - 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)) = 0, - toDecimal64(1, - 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'USD', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)))))) AS amount - FROM events - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, - events__override.distinct_id) - WHERE and(equals(events.team_id, - 99999), and(equals(events.event, - 'purchase'), 1, - isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, - isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', - 6, - 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', - 6, - 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL - SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, - 'UTC') AS timestamp, - accurateCastOrNull(0, - 'Decimal64(10)') AS amount - FROM ( - SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', - 6, - 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', - 6, - 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', - 6, - 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', - 6, - 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, - mrr_agg.customer_id)) AS e__poe__revenue_analytics ON equals(toString(if(not(empty(e__override.distinct_id)), e__override.person_id, - e.person_id)), toString(e__poe__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, - 99999), greaterOrEquals(toTimeZone(e.timestamp, - 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', - 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, - 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', - 'UTC'))), equals(e.event, - '$pageview')) - GROUP BY day_start, - breakdown_value_1) - GROUP BY day_start, - breakdown_value_1 - ORDER BY day_start ASC, - breakdown_value ASC) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, - '$$_posthog_breakdown_other_$$'), 2, - if(has(breakdown_value, - '$$_posthog_breakdown_null_$$'), 1, - 0)) ASC, arraySum(total) DESC, breakdown_value ASC) - WHERE arrayExists(x -> isNotNull(x), breakdown_value) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, - '$$_posthog_breakdown_other_$$'), 2, - if(has(breakdown_value, - '$$_posthog_breakdown_null_$$'), 1, - 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_3_person_id_override_properties_joined - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_3_person_id_override_properties_joined.1 - ''' - SELECT groupArray(1)(date)[1] AS date, arrayFold((acc, x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, plus(length(date), 1))), groupArray(ifNull(total, 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, 25), 0), 0), '$$_posthog_breakdown_other_$$', i), breakdown_value) AS breakdown_value - FROM ( - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, 0)), indexOf(groupArray(day_start) AS _days_for_count, _match_date) AS _index, plus(minus(arrayLastIndex(x -> ifNull(equals(x, _match_date), isNull(x) - and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, breakdown_value AS breakdown_value, rowNumberInAllBlocks() AS row_number - FROM ( - SELECT sum(total) AS count, day_start AS day_start, [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM ( - SELECT count() AS total, toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, ifNull(nullIf(leftUTF8(toString(e__person__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__override ON equals(e.distinct_id, e__override.distinct_id) - LEFT JOIN ( - SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS e__person___id, person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__person ON equals(if(not(empty(e__override.distinct_id)), e__override.person_id, e.person_id), e__person.e__person___id) - LEFT JOIN ( - SELECT 99999 AS team_id, revenue_analytics_customer.id AS person_id, coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM ( - SELECT toString(persons.id) AS id, 'revenue_analytics.events.purchase' AS source_label, persons.created_at AS timestamp, persons.properties___name AS name, persons.properties___email AS email, persons.properties___phone AS phone, persons.properties___address AS address, persons.properties___metadata AS metadata, persons.`properties___$geoip_country_name` AS country, formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, NULL AS initial_coupon, NULL AS initial_coupon_id - FROM ( - SELECT person.id AS id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), ( - SELECT person.id AS id, max(person.version) AS version - FROM person WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN ( - SELECT DISTINCT events__person.id AS person_id - FROM events - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - LEFT JOIN ( - SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN ( - SELECT revenue_analytics_revenue_item.customer_id AS customer_id, sum(revenue_analytics_revenue_item.amount) AS revenue - FROM ( - SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN ( - SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM ( - SELECT union.source_label AS source_label, union.customer_id AS customer_id, union.subscription_id AS subscription_id, argMax(union.amount, union.timestamp) AS mrr - FROM ( - SELECT revenue_item.source_label AS source_label, revenue_item.customer_id AS customer_id, revenue_item.subscription_id AS subscription_id, toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, sum(revenue_item.amount) AS amount - FROM ( - SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) - GROUP BY revenue_item.source_label, revenue_item.customer_id, revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL - SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM ( - SELECT '' AS id, '' AS source_label, '' AS plan_id, '' AS product_id, '' AS customer_id, '' AS status, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, customer_id, subscription_id - ORDER BY customer_id ASC, subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__person__revenue_analytics ON equals(toString(e__person.e__person___id), toString(e__person__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, breakdown_value_1) - GROUP BY day_start, breakdown_value_1 - ORDER BY day_start ASC, breakdown_value ASC) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC) - WHERE arrayExists(x -> isNotNull(x), breakdown_value) - GROUP BY breakdown_value - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0, transform_null_in=1, optimize_min_equality_disjunction_chain_length=4294967295, allow_experimental_join_condition=1, use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_0_disabled - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_0_disabled.1 - ''' - WITH breakdown_series AS - (SELECT count AS count, - day_start AS day_start, - breakdown_value AS breakdown_value - FROM - (SELECT sum(total) AS count, - day_start AS day_start, - [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM - (SELECT count() AS total, - toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, - ifNull(nullIf(leftUTF8(toString(e__pdi__person__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - INNER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS e__pdi___person_id, - tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__pdi ON equals(e.distinct_id, e__pdi.distinct_id) - INNER JOIN - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS e__pdi__person___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__pdi__person ON equals(e__pdi.e__pdi___person_id, e__pdi__person.e__pdi__person___id) - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events__pdi__person.id AS person_id - FROM events - INNER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS events__pdi___person_id, - tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) - INNER JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__pdi__person ON equals(events__pdi.events__pdi___person_id, events__pdi__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(events__pdi.person_id) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - INNER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(events__pdi.person_id) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - INNER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id2.person_id), person_distinct_id2.version), 1) AS person_id, - person_distinct_id2.distinct_id AS distinct_id - FROM person_distinct_id2 - WHERE equals(person_distinct_id2.team_id, 99999) - GROUP BY person_distinct_id2.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id2.is_deleted), person_distinct_id2.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__pdi ON equals(events.distinct_id, events__pdi.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__pdi__person__revenue_analytics ON equals(toString(e__pdi__person.e__pdi__person___id), toString(e__pdi__person__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, - breakdown_value_1) - GROUP BY day_start, - breakdown_value_1 - ORDER BY day_start ASC, - breakdown_value ASC)), - totals_per_breakdown AS - (SELECT breakdown_series.breakdown_value AS breakdown_value, - sum(breakdown_series.count) AS total_count_for_breakdown, - if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) AS ordering - FROM breakdown_series - GROUP BY breakdown_series.breakdown_value), - ranked_breakdown_totals AS - (SELECT totals_per_breakdown.breakdown_value AS breakdown_value, - totals_per_breakdown.ordering AS ordering, - totals_per_breakdown.total_count_for_breakdown AS total_count_for_breakdown, - row_number() OVER ( - ORDER BY totals_per_breakdown.ordering ASC, totals_per_breakdown.total_count_for_breakdown DESC, totals_per_breakdown.breakdown_value ASC) AS breakdown_rank - FROM totals_per_breakdown), - ranked_breakdown_values AS - (SELECT breakdown_series.count AS count, - toTimeZone(breakdown_series.day_start, 'UTC') AS day_start, - breakdown_series.breakdown_value AS breakdown_value, - ranked_breakdown_totals.ordering AS ordering, - ranked_breakdown_totals.breakdown_rank AS breakdown_rank - FROM breakdown_series - JOIN ranked_breakdown_totals ON equals(ranked_breakdown_totals.breakdown_value, breakdown_series.breakdown_value)), - top_n_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - ranked_breakdown_values.count AS value, - ranked_breakdown_values.breakdown_value AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(lessOrEquals(ranked_breakdown_values.breakdown_rank, 25), 0)), - other_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - sum(ranked_breakdown_values.count) AS value, - ['$$_posthog_breakdown_other_$$'] AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(greater(ranked_breakdown_values.breakdown_rank, 25), 0) - GROUP BY toTimeZone(ranked_breakdown_values.day_start, 'UTC')), - top_n_and_other_breakdown_values AS - (SELECT day_start AS day_start, - value AS value, - breakdown_value AS breakdown_value - FROM - (SELECT toTimeZone(top_n_breakdown_values.day_start, 'UTC') AS day_start, - top_n_breakdown_values.value AS value, - top_n_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_breakdown_values - UNION ALL SELECT toTimeZone(other_breakdown_values.day_start, 'UTC') AS day_start, - other_breakdown_values.value AS value, - other_breakdown_values.breakdown_value AS breakdown_value - FROM other_breakdown_values) - ORDER BY day_start ASC, - value ASC) - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, - arrayMap(d -> arraySum(arrayMap((v, dd) -> if(ifNull(equals(dd, d), isNull(dd) - and isNull(d)), v, 0), vals, days)), date) AS total, - breakdown_value AS breakdown_value - FROM - (SELECT groupArray(toTimeZone(top_n_and_other_breakdown_values.day_start, 'UTC')) AS days, - groupArray(top_n_and_other_breakdown_values.value) AS vals, - top_n_and_other_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_and_other_breakdown_values - GROUP BY top_n_and_other_breakdown_values.breakdown_value) - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_1_person_id_no_override_properties_on_events - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_1_person_id_no_override_properties_on_events.1 - ''' - WITH breakdown_series AS - (SELECT count AS count, - day_start AS day_start, - breakdown_value AS breakdown_value - FROM - (SELECT sum(total) AS count, - day_start AS day_start, - [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM - (SELECT count() AS total, - toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, - ifNull(nullIf(leftUTF8(toString(e__poe__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events.person_id AS person_id - FROM events - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(events.person_id) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(events.person_id) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__poe__revenue_analytics ON equals(toString(e.person_id), toString(e__poe__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, - breakdown_value_1) - GROUP BY day_start, - breakdown_value_1 - ORDER BY day_start ASC, - breakdown_value ASC)), - totals_per_breakdown AS - (SELECT breakdown_series.breakdown_value AS breakdown_value, - sum(breakdown_series.count) AS total_count_for_breakdown, - if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) AS ordering - FROM breakdown_series - GROUP BY breakdown_series.breakdown_value), - ranked_breakdown_totals AS - (SELECT totals_per_breakdown.breakdown_value AS breakdown_value, - totals_per_breakdown.ordering AS ordering, - totals_per_breakdown.total_count_for_breakdown AS total_count_for_breakdown, - row_number() OVER ( - ORDER BY totals_per_breakdown.ordering ASC, totals_per_breakdown.total_count_for_breakdown DESC, totals_per_breakdown.breakdown_value ASC) AS breakdown_rank - FROM totals_per_breakdown), - ranked_breakdown_values AS - (SELECT breakdown_series.count AS count, - toTimeZone(breakdown_series.day_start, 'UTC') AS day_start, - breakdown_series.breakdown_value AS breakdown_value, - ranked_breakdown_totals.ordering AS ordering, - ranked_breakdown_totals.breakdown_rank AS breakdown_rank - FROM breakdown_series - JOIN ranked_breakdown_totals ON equals(ranked_breakdown_totals.breakdown_value, breakdown_series.breakdown_value)), - top_n_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - ranked_breakdown_values.count AS value, - ranked_breakdown_values.breakdown_value AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(lessOrEquals(ranked_breakdown_values.breakdown_rank, 25), 0)), - other_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - sum(ranked_breakdown_values.count) AS value, - ['$$_posthog_breakdown_other_$$'] AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(greater(ranked_breakdown_values.breakdown_rank, 25), 0) - GROUP BY toTimeZone(ranked_breakdown_values.day_start, 'UTC')), - top_n_and_other_breakdown_values AS - (SELECT day_start AS day_start, - value AS value, - breakdown_value AS breakdown_value - FROM - (SELECT toTimeZone(top_n_breakdown_values.day_start, 'UTC') AS day_start, - top_n_breakdown_values.value AS value, - top_n_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_breakdown_values - UNION ALL SELECT toTimeZone(other_breakdown_values.day_start, 'UTC') AS day_start, - other_breakdown_values.value AS value, - other_breakdown_values.breakdown_value AS breakdown_value - FROM other_breakdown_values) - ORDER BY day_start ASC, - value ASC) - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, - arrayMap(d -> arraySum(arrayMap((v, dd) -> if(ifNull(equals(dd, d), isNull(dd) - and isNull(d)), v, 0), vals, days)), date) AS total, - breakdown_value AS breakdown_value - FROM - (SELECT groupArray(toTimeZone(top_n_and_other_breakdown_values.day_start, 'UTC')) AS days, - groupArray(top_n_and_other_breakdown_values.value) AS vals, - top_n_and_other_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_and_other_breakdown_values - GROUP BY top_n_and_other_breakdown_values.breakdown_value) - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_2_person_id_override_properties_on_events - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp - FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_2_person_id_override_properties_on_events.1 - ''' - WITH breakdown_series AS - (SELECT count AS count, - day_start AS day_start, - breakdown_value AS breakdown_value - FROM - (SELECT sum(total) AS count, - day_start AS day_start, - [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM - (SELECT count() AS total, - toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, - ifNull(nullIf(leftUTF8(toString(e__poe__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__override ON equals(e.distinct_id, e__override.distinct_id) - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id) AS person_id - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__poe__revenue_analytics ON equals(toString(if(not(empty(e__override.distinct_id)), e__override.person_id, e.person_id)), toString(e__poe__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, - breakdown_value_1) - GROUP BY day_start, - breakdown_value_1 - ORDER BY day_start ASC, - breakdown_value ASC)), - totals_per_breakdown AS - (SELECT breakdown_series.breakdown_value AS breakdown_value, - sum(breakdown_series.count) AS total_count_for_breakdown, - if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) AS ordering - FROM breakdown_series - GROUP BY breakdown_series.breakdown_value), - ranked_breakdown_totals AS - (SELECT totals_per_breakdown.breakdown_value AS breakdown_value, - totals_per_breakdown.ordering AS ordering, - totals_per_breakdown.total_count_for_breakdown AS total_count_for_breakdown, - row_number() OVER ( - ORDER BY totals_per_breakdown.ordering ASC, totals_per_breakdown.total_count_for_breakdown DESC, totals_per_breakdown.breakdown_value ASC) AS breakdown_rank - FROM totals_per_breakdown), - ranked_breakdown_values AS - (SELECT breakdown_series.count AS count, - toTimeZone(breakdown_series.day_start, 'UTC') AS day_start, - breakdown_series.breakdown_value AS breakdown_value, - ranked_breakdown_totals.ordering AS ordering, - ranked_breakdown_totals.breakdown_rank AS breakdown_rank - FROM breakdown_series - JOIN ranked_breakdown_totals ON equals(ranked_breakdown_totals.breakdown_value, breakdown_series.breakdown_value)), - top_n_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - ranked_breakdown_values.count AS value, - ranked_breakdown_values.breakdown_value AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(lessOrEquals(ranked_breakdown_values.breakdown_rank, 25), 0)), - other_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - sum(ranked_breakdown_values.count) AS value, - ['$$_posthog_breakdown_other_$$'] AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(greater(ranked_breakdown_values.breakdown_rank, 25), 0) - GROUP BY toTimeZone(ranked_breakdown_values.day_start, 'UTC')), - top_n_and_other_breakdown_values AS - (SELECT day_start AS day_start, - value AS value, - breakdown_value AS breakdown_value - FROM - (SELECT toTimeZone(top_n_breakdown_values.day_start, 'UTC') AS day_start, - top_n_breakdown_values.value AS value, - top_n_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_breakdown_values - UNION ALL SELECT toTimeZone(other_breakdown_values.day_start, 'UTC') AS day_start, - other_breakdown_values.value AS value, - other_breakdown_values.breakdown_value AS breakdown_value - FROM other_breakdown_values) - ORDER BY day_start ASC, - value ASC) - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, - arrayMap(d -> arraySum(arrayMap((v, dd) -> if(ifNull(equals(dd, d), isNull(dd) - and isNull(d)), v, 0), vals, days)), date) AS total, - breakdown_value AS breakdown_value - FROM - (SELECT groupArray(toTimeZone(top_n_and_other_breakdown_values.day_start, 'UTC')) AS days, - groupArray(top_n_and_other_breakdown_values.value) AS vals, - top_n_and_other_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_and_other_breakdown_values - GROUP BY top_n_and_other_breakdown_values.breakdown_value) - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC - LIMIT 50000 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_3_person_id_override_properties_joined - ''' - SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp + SELECT groupArray(1)(date)[1] AS date, + arrayFold((acc, + x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, + plus(length(date), 1))), groupArray(ifNull(total, + 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, + arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, + 25), 0), 0), '$$_posthog_breakdown_other_$$', + i), breakdown_value) AS breakdown_value + FROM ( + SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', + 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, + plus(coalesce(dateDiff('day', + toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', + 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', + 'UTC')), toIntervalDay(1)))), 1))) AS date, + arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, + 0)), indexOf(groupArray(day_start) AS _days_for_count, + _match_date) AS _index, + plus(minus(arrayLastIndex(x -> ifNull(equals(x, + _match_date), isNull(x) + and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, + breakdown_value AS breakdown_value, + rowNumberInAllBlocks() AS row_number + FROM ( + SELECT sum(total) AS count, + day_start AS day_start, + [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value + FROM ( + SELECT count() AS total, + toStartOfDay(toTimeZone(e.timestamp, + 'UTC')) AS day_start, + ifNull(nullIf(leftUTF8(toString(e__poe__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 + FROM events AS e + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, + 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__override ON equals(e.distinct_id, + e__override.distinct_id) + LEFT JOIN ( + SELECT 99999 AS team_id, + revenue_analytics_customer.id AS person_id, + coalesce(revenue_agg.revenue, + accurateCastOrNull(0, + 'Decimal64(10)')) AS revenue, + coalesce(mrr_agg.mrr, + accurateCastOrNull(0, + 'Decimal64(10)')) AS mrr + FROM ( + SELECT toString(persons.id) AS id, + 'revenue_analytics.events.purchase' AS source_label, + persons.created_at AS timestamp, + persons.properties___name AS name, + persons.properties___email AS email, + persons.properties___phone AS phone, + persons.properties___address AS address, + persons.properties___metadata AS metadata, + persons.`properties___$geoip_country_name` AS country, + formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, + NULL AS initial_coupon, + NULL AS initial_coupon_id + FROM ( + SELECT person.id AS id, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, + 'name'), ''), 'null'), '^"|"$', + '') AS properties___name, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, + 'email'), ''), 'null'), '^"|"$', + '') AS properties___email, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, + 'phone'), ''), 'null'), '^"|"$', + '') AS properties___phone, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, + 'address'), ''), 'null'), '^"|"$', + '') AS properties___address, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, + 'metadata'), ''), 'null'), '^"|"$', + '') AS properties___metadata, + replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, + '$geoip_country_name'), ''), 'null'), '^"|"$', + '') AS `properties___$geoip_country_name`, + toTimeZone(person.created_at, + 'UTC') AS created_at + FROM person + WHERE and(equals(person.team_id, + 99999), in(tuple(person.id, + person.version), ( + SELECT person.id AS id, + max(person.version) AS version + FROM person WHERE equals(person.team_id, + 99999) + GROUP BY person.id + HAVING and(ifNull(equals(argMax(person.is_deleted, + person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, + 'UTC'), person.version), plus(now64(6, + 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons + INNER JOIN ( + SELECT DISTINCT if(not(empty(events__override.distinct_id)), events__override.person_id, + events.person_id) AS person_id FROM events - WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) - ORDER BY toTimeZone(events.timestamp, 'UTC') ASC - LIMIT 1 SETTINGS readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 - ''' -# --- -# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_with_managed_viewsets_ff_3_person_id_override_properties_joined.1 - ''' - WITH breakdown_series AS - (SELECT count AS count, - day_start AS day_start, - breakdown_value AS breakdown_value - FROM - (SELECT sum(total) AS count, - day_start AS day_start, - [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value - FROM - (SELECT count() AS total, - toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, - ifNull(nullIf(leftUTF8(toString(e__person__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 - FROM events AS e - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__override ON equals(e.distinct_id, e__override.distinct_id) - INNER JOIN - (SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS e__person___id, - person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__person ON equals(if(not(empty(e__override.distinct_id)), e__override.person_id, e.person_id), e__person.e__person___id) - LEFT JOIN - (SELECT 99999 AS team_id, - revenue_analytics_customer.id AS person_id, - coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, - coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr - FROM - (SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id - FROM - (SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, 'UTC') AS created_at - FROM person - WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), - (SELECT person.id AS id, max(person.version) AS version - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons - INNER JOIN - (SELECT DISTINCT events__person.id AS person_id - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - INNER JOIN - (SELECT person.id AS id - FROM person - WHERE equals(person.team_id, 99999) - GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) - WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer - LEFT JOIN - (SELECT revenue_analytics_revenue_item.customer_id AS customer_id, - sum(revenue_analytics_revenue_item.amount) AS revenue - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, + 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, + events__override.distinct_id) + WHERE equals(events.team_id, + 99999)) AS events ON equals(persons.id, + events.person_id) + ORDER BY persons.created_at DESC) AS revenue_analytics_customer + LEFT JOIN ( + SELECT revenue_analytics_revenue_item.customer_id AS customer_id, + sum(revenue_analytics_revenue_item.amount) AS revenue + FROM ( + SELECT toString(events.uuid) AS id, + toString(events.uuid) AS invoice_item_id, + 'revenue_analytics.events.purchase' AS source_label, + toTimeZone(events.timestamp, + 'UTC') AS timestamp, + timestamp AS created_at, + 0 AS is_recurring, + NULL AS product_id, + toString(if(not(empty(events__override.distinct_id)), events__override.person_id, + events.person_id)) AS customer_id, + events.`$group_0` AS group_0_key, + events.`$group_1` AS group_1_key, + events.`$group_2` AS group_2_key, + events.`$group_3` AS group_3_key, + events.`$group_4` AS group_4_key, + NULL AS invoice_id, + NULL AS subscription_id, + toString(events.`$session_id`) AS session_id, + events.event AS event_name, + NULL AS coupon, + coupon AS coupon_id, + 'USD' AS original_currency, + accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, + 'revenue'), ''), 'null'), '^"|"$', + ''), 'Decimal64(10)') AS original_amount, + in(original_currency, + ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, + if(enable_currency_aware_divider, + accurateCastOrNull(1, + 'Decimal64(10)'), accurateCastOrNull(100, + 'Decimal64(10)')) AS currency_aware_divider, + divideDecimal(original_amount, + currency_aware_divider) AS currency_aware_amount, + 'USD' AS currency, + if(isNull('USD'), accurateCastOrNull(currency_aware_amount, + 'Decimal64(10)'), if(equals('USD', + 'USD'), toDecimal64(currency_aware_amount, + 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)) = 0, + toDecimal64(0, + 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, + 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)) = 0, + toDecimal64(1, + 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)))))) AS amount + FROM events + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, + 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, + events__override.distinct_id) + WHERE and(equals(events.team_id, + 99999), and(equals(events.event, + 'purchase'), 1, + isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_analytics_revenue_item + GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, + revenue_agg.customer_id) + LEFT JOIN ( + SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, + sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr + FROM ( + SELECT union.source_label AS source_label, + union.customer_id AS customer_id, + union.subscription_id AS subscription_id, + argMax(union.amount, + union.timestamp) AS mrr + FROM ( + SELECT revenue_item.source_label AS source_label, + revenue_item.customer_id AS customer_id, + revenue_item.subscription_id AS subscription_id, + toStartOfMonth(toTimeZone(revenue_item.timestamp, + 'UTC')) AS timestamp, + sum(revenue_item.amount) AS amount + FROM ( + SELECT toString(events.uuid) AS id, + toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item - GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) - LEFT JOIN - (SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, - sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr - FROM - (SELECT union.source_label AS source_label, - union.customer_id AS customer_id, - union.subscription_id AS subscription_id, - argMax(union.amount, union.timestamp) AS mrr - FROM - (SELECT revenue_item.source_label AS source_label, - revenue_item.customer_id AS customer_id, - revenue_item.subscription_id AS subscription_id, - toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, - sum(revenue_item.amount) AS amount - FROM - (SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, 'UTC') AS timestamp, - timestamp AS created_at, - 0 AS is_recurring, - NULL AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - NULL AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - NULL AS coupon, - coupon AS coupon_id, - 'USD' AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, - 'USD' AS currency, - if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount - FROM events - LEFT OUTER JOIN - (SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id - FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, 99999) - GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) - WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_item - WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - GROUP BY revenue_item.source_label, - revenue_item.customer_id, - revenue_item.subscription_id, timestamp - ORDER BY timestamp DESC - UNION ALL SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, - `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, - toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, - accurateCastOrNull(0, 'Decimal64(10)') AS amount - FROM - (SELECT '' AS id, - '' AS source_label, - '' AS plan_id, - '' AS product_id, - '' AS customer_id, - '' AS status, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, - toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, - '' AS metadata - WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` - WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('today', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('today', 6, 'UTC'))) - ORDER BY timestamp DESC) AS - union - GROUP BY source_label, - customer_id, - subscription_id - ORDER BY customer_id ASC, - subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` - GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__person__revenue_analytics ON equals(toString(e__person.e__person___id), toString(e__person__revenue_analytics.person_id)) - WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) - GROUP BY day_start, - breakdown_value_1) - GROUP BY day_start, - breakdown_value_1 - ORDER BY day_start ASC, - breakdown_value ASC)), - totals_per_breakdown AS - (SELECT breakdown_series.breakdown_value AS breakdown_value, - sum(breakdown_series.count) AS total_count_for_breakdown, - if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_series.breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) AS ordering - FROM breakdown_series - GROUP BY breakdown_series.breakdown_value), - ranked_breakdown_totals AS - (SELECT totals_per_breakdown.breakdown_value AS breakdown_value, - totals_per_breakdown.ordering AS ordering, - totals_per_breakdown.total_count_for_breakdown AS total_count_for_breakdown, - row_number() OVER ( - ORDER BY totals_per_breakdown.ordering ASC, totals_per_breakdown.total_count_for_breakdown DESC, totals_per_breakdown.breakdown_value ASC) AS breakdown_rank - FROM totals_per_breakdown), - ranked_breakdown_values AS - (SELECT breakdown_series.count AS count, - toTimeZone(breakdown_series.day_start, 'UTC') AS day_start, - breakdown_series.breakdown_value AS breakdown_value, - ranked_breakdown_totals.ordering AS ordering, - ranked_breakdown_totals.breakdown_rank AS breakdown_rank - FROM breakdown_series - JOIN ranked_breakdown_totals ON equals(ranked_breakdown_totals.breakdown_value, breakdown_series.breakdown_value)), - top_n_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - ranked_breakdown_values.count AS value, - ranked_breakdown_values.breakdown_value AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(lessOrEquals(ranked_breakdown_values.breakdown_rank, 25), 0)), - other_breakdown_values AS - (SELECT toTimeZone(ranked_breakdown_values.day_start, 'UTC') AS day_start, - sum(ranked_breakdown_values.count) AS value, - ['$$_posthog_breakdown_other_$$'] AS breakdown_value - FROM ranked_breakdown_values - WHERE ifNull(greater(ranked_breakdown_values.breakdown_rank, 25), 0) - GROUP BY toTimeZone(ranked_breakdown_values.day_start, 'UTC')), - top_n_and_other_breakdown_values AS - (SELECT day_start AS day_start, - value AS value, - breakdown_value AS breakdown_value - FROM - (SELECT toTimeZone(top_n_breakdown_values.day_start, 'UTC') AS day_start, - top_n_breakdown_values.value AS value, - top_n_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_breakdown_values - UNION ALL SELECT toTimeZone(other_breakdown_values.day_start, 'UTC') AS day_start, - other_breakdown_values.value AS value, - other_breakdown_values.breakdown_value AS breakdown_value - FROM other_breakdown_values) - ORDER BY day_start ASC, - value ASC) - SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, - arrayMap(d -> arraySum(arrayMap((v, dd) -> if(ifNull(equals(dd, d), isNull(dd) - and isNull(d)), v, 0), vals, days)), date) AS total, - breakdown_value AS breakdown_value - FROM - (SELECT groupArray(toTimeZone(top_n_and_other_breakdown_values.day_start, 'UTC')) AS days, - groupArray(top_n_and_other_breakdown_values.value) AS vals, - top_n_and_other_breakdown_values.breakdown_value AS breakdown_value - FROM top_n_and_other_breakdown_values - GROUP BY top_n_and_other_breakdown_values.breakdown_value) - ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC + toTimeZone(events.timestamp, + 'UTC') AS timestamp, + timestamp AS created_at, + 0 AS is_recurring, + NULL AS product_id, + toString(if(not(empty(events__override.distinct_id)), events__override.person_id, + events.person_id)) AS customer_id, + events.`$group_0` AS group_0_key, + events.`$group_1` AS group_1_key, + events.`$group_2` AS group_2_key, + events.`$group_3` AS group_3_key, + events.`$group_4` AS group_4_key, + NULL AS invoice_id, + NULL AS subscription_id, + toString(events.`$session_id`) AS session_id, + events.event AS event_name, + NULL AS coupon, + coupon AS coupon_id, + 'USD' AS original_currency, + accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, + 'revenue'), ''), 'null'), '^"|"$', + ''), 'Decimal64(10)') AS original_amount, + in(original_currency, + ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, + if(enable_currency_aware_divider, + accurateCastOrNull(1, + 'Decimal64(10)'), accurateCastOrNull(100, + 'Decimal64(10)')) AS currency_aware_divider, + divideDecimal(original_amount, + currency_aware_divider) AS currency_aware_amount, + 'USD' AS currency, + if(isNull('USD'), accurateCastOrNull(currency_aware_amount, + 'Decimal64(10)'), if(equals('USD', + 'USD'), toDecimal64(currency_aware_amount, + 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)) = 0, + toDecimal64(0, + 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, + 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)) = 0, + toDecimal64(1, + 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, + 'rate', + 'USD', + toDate(toTimeZone(events.timestamp, + 'UTC')), toDecimal64(0, + 10)))))) AS amount + FROM events + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, + person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, + 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, + events__override.distinct_id) + WHERE and(equals(events.team_id, + 99999), and(equals(events.event, + 'purchase'), 1, + isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_item + WHERE and(revenue_item.is_recurring, + isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', + 6, + 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', + 6, + 'UTC'))) + GROUP BY revenue_item.source_label, + revenue_item.customer_id, + revenue_item.subscription_id, timestamp + ORDER BY timestamp DESC + UNION ALL + SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, + `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, + `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, + toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, + 'UTC') AS timestamp, + accurateCastOrNull(0, + 'Decimal64(10)') AS amount + FROM ( + SELECT '' AS id, + '' AS source_label, + '' AS plan_id, + '' AS product_id, + '' AS customer_id, + '' AS status, + toDateTime64('1970-01-01 00:00:00.000000', + 6, + 'UTC') AS started_at, + toDateTime64('1970-01-01 00:00:00.000000', + 6, + 'UTC') AS ended_at, + '' AS metadata + WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', + 6, + 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', + 6, + 'UTC'))) + ORDER BY timestamp DESC) AS + union + GROUP BY source_label, + customer_id, + subscription_id + ORDER BY customer_id ASC, + subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` + GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, + mrr_agg.customer_id)) AS e__poe__revenue_analytics ON equals(toString(if(not(empty(e__override.distinct_id)), e__override.person_id, + e.person_id)), toString(e__poe__revenue_analytics.person_id)) + WHERE and(equals(e.team_id, + 99999), greaterOrEquals(toTimeZone(e.timestamp, + 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', + 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, + 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', + 'UTC'))), equals(e.event, + '$pageview')) + GROUP BY day_start, + breakdown_value_1) + GROUP BY day_start, + breakdown_value_1 + ORDER BY day_start ASC, + breakdown_value ASC) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, + '$$_posthog_breakdown_other_$$'), 2, + if(has(breakdown_value, + '$$_posthog_breakdown_null_$$'), 1, + 0)) ASC, arraySum(total) DESC, breakdown_value ASC) + WHERE arrayExists(x -> isNotNull(x), breakdown_value) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, + '$$_posthog_breakdown_other_$$'), 2, + if(has(breakdown_value, + '$$_posthog_breakdown_null_$$'), 1, + 0)) ASC, arraySum(total) DESC, breakdown_value ASC LIMIT 50000 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, @@ -4993,6 +2841,132 @@ use_hive_partitioning=0 ''' # --- +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_3_person_id_override_properties_joined + ''' + SELECT toTimeZone(events.timestamp, 'UTC') AS timestamp + FROM events + WHERE and(equals(events.team_id, 99999), greater(toTimeZone(events.timestamp, 'UTC'), toDateTime64('1980-01-01 00:00:00.000000', 6, 'UTC')), equals(events.event, '$pageview')) + ORDER BY toTimeZone(events.timestamp, 'UTC') ASC + LIMIT 1 SETTINGS readonly=2, + max_execution_time=60, + allow_experimental_object_type=1, + max_ast_elements=4000000, + max_expanded_ast_elements=4000000, + max_bytes_before_external_group_by=0, + transform_null_in=1, + optimize_min_equality_disjunction_chain_length=4294967295, + allow_experimental_join_condition=1, + use_hive_partitioning=0 + ''' +# --- +# name: TestPersonsRevenueAnalytics.test_virtual_property_in_trend_3_person_id_override_properties_joined.1 + ''' + SELECT groupArray(1)(date)[1] AS date, arrayFold((acc, x) -> arrayMap(i -> plus(acc[i], x[i]), range(1, plus(length(date), 1))), groupArray(ifNull(total, 0)), arrayWithConstant(length(date), reinterpretAsFloat64(0))) AS total, arrayMap(i -> if(ifNull(ifNull(greaterOrEquals(row_number, 25), 0), 0), '$$_posthog_breakdown_other_$$', i), breakdown_value) AS breakdown_value + FROM ( + SELECT arrayMap(number -> plus(toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toIntervalDay(number)), range(0, plus(coalesce(dateDiff('day', toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1)), toStartOfInterval(assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC')), toIntervalDay(1)))), 1))) AS date, arrayMap(_match_date -> arraySum(arraySlice(groupArray(ifNull(count, 0)), indexOf(groupArray(day_start) AS _days_for_count, _match_date) AS _index, plus(minus(arrayLastIndex(x -> ifNull(equals(x, _match_date), isNull(x) + and isNull(_match_date)), _days_for_count), _index), 1))), date) AS total, breakdown_value AS breakdown_value, rowNumberInAllBlocks() AS row_number + FROM ( + SELECT sum(total) AS count, day_start AS day_start, [ifNull(toString(breakdown_value_1), '$$_posthog_breakdown_null_$$')] AS breakdown_value + FROM ( + SELECT count() AS total, toStartOfDay(toTimeZone(e.timestamp, 'UTC')) AS day_start, ifNull(nullIf(leftUTF8(toString(e__person__revenue_analytics.revenue), 400), ''), '$$_posthog_breakdown_null_$$') AS breakdown_value_1 + FROM events AS e + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS e__override ON equals(e.distinct_id, e__override.distinct_id) + LEFT JOIN ( + SELECT tupleElement(argMax(tuple(person.id), person.version), 1) AS e__person___id, person.id AS id + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS e__person ON equals(if(not(empty(e__override.distinct_id)), e__override.person_id, e.person_id), e__person.e__person___id) + LEFT JOIN ( + SELECT 99999 AS team_id, revenue_analytics_customer.id AS person_id, coalesce(revenue_agg.revenue, accurateCastOrNull(0, 'Decimal64(10)')) AS revenue, coalesce(mrr_agg.mrr, accurateCastOrNull(0, 'Decimal64(10)')) AS mrr + FROM ( + SELECT toString(persons.id) AS id, 'revenue_analytics.events.purchase' AS source_label, persons.created_at AS timestamp, persons.properties___name AS name, persons.properties___email AS email, persons.properties___phone AS phone, persons.properties___address AS address, persons.properties___metadata AS metadata, persons.`properties___$geoip_country_name` AS country, formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, NULL AS initial_coupon, NULL AS initial_coupon_id + FROM ( + SELECT person.id AS id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, toTimeZone(person.created_at, 'UTC') AS created_at + FROM person + WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), ( + SELECT person.id AS id, max(person.version) AS version + FROM person WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons + INNER JOIN ( + SELECT DISTINCT events__person.id AS person_id + FROM events + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + LEFT JOIN ( + SELECT person.id AS id + FROM person + WHERE equals(person.team_id, 99999) + GROUP BY person.id + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) + WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) + ORDER BY persons.created_at DESC) AS revenue_analytics_customer + LEFT JOIN ( + SELECT revenue_analytics_revenue_item.customer_id AS customer_id, sum(revenue_analytics_revenue_item.amount) AS revenue + FROM ( + SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_analytics_revenue_item + GROUP BY customer_id) AS revenue_agg ON equals(revenue_analytics_customer.id, revenue_agg.customer_id) + LEFT JOIN ( + SELECT `revenue_analytics.events.purchase.mrr_events_revenue_view`.customer_id AS customer_id, sum(`revenue_analytics.events.purchase.mrr_events_revenue_view`.mrr) AS mrr + FROM ( + SELECT union.source_label AS source_label, union.customer_id AS customer_id, union.subscription_id AS subscription_id, argMax(union.amount, union.timestamp) AS mrr + FROM ( + SELECT revenue_item.source_label AS source_label, revenue_item.customer_id AS customer_id, revenue_item.subscription_id AS subscription_id, toStartOfMonth(toTimeZone(revenue_item.timestamp, 'UTC')) AS timestamp, sum(revenue_item.amount) AS amount + FROM ( + SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, 0 AS is_recurring, NULL AS product_id, toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, NULL AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, NULL AS coupon, coupon AS coupon_id, 'USD' AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'USD' AS currency, if(isNull('USD'), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals('USD', 'USD'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'USD', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount + FROM events + LEFT OUTER JOIN ( + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id + FROM person_distinct_id_overrides + WHERE equals(person_distinct_id_overrides.team_id, 99999) + GROUP BY person_distinct_id_overrides.distinct_id + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_item + WHERE and(revenue_item.is_recurring, isNotNull(revenue_item.subscription_id), greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) + GROUP BY revenue_item.source_label, revenue_item.customer_id, revenue_item.subscription_id, timestamp + ORDER BY timestamp DESC + UNION ALL + SELECT `revenue_analytics.events.purchase.subscription_events_revenue_view`.source_label AS source_label, `revenue_analytics.events.purchase.subscription_events_revenue_view`.customer_id AS customer_id, `revenue_analytics.events.purchase.subscription_events_revenue_view`.id AS subscription_id, toTimeZone(`revenue_analytics.events.purchase.subscription_events_revenue_view`.ended_at, 'UTC') AS timestamp, accurateCastOrNull(0, 'Decimal64(10)') AS amount + FROM ( + SELECT '' AS id, '' AS source_label, '' AS plan_id, '' AS product_id, '' AS customer_id, '' AS status, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS started_at, toDateTime64('1970-01-01 00:00:00.000000', 6, 'UTC') AS ended_at, '' AS metadata + WHERE 0) AS `revenue_analytics.events.purchase.subscription_events_revenue_view` WHERE and(greaterOrEquals(timestamp, toStartOfMonth(addDays(toDateTime64('explicit_redacted_timestamp', 6, 'UTC'), -60))), lessOrEquals(timestamp, toDateTime64('explicit_redacted_timestamp', 6, 'UTC'))) + ORDER BY timestamp DESC) AS + union + GROUP BY source_label, customer_id, subscription_id + ORDER BY customer_id ASC, subscription_id ASC) AS `revenue_analytics.events.purchase.mrr_events_revenue_view` + GROUP BY customer_id) AS mrr_agg ON equals(revenue_analytics_customer.id, mrr_agg.customer_id)) AS e__person__revenue_analytics ON equals(toString(e__person.e__person___id), toString(e__person__revenue_analytics.person_id)) + WHERE and(equals(e.team_id, 99999), greaterOrEquals(toTimeZone(e.timestamp, 'UTC'), toStartOfInterval(assumeNotNull(toDateTime('2025-05-29 00:00:00', 'UTC')), toIntervalDay(1))), lessOrEquals(toTimeZone(e.timestamp, 'UTC'), assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), equals(e.event, '$pageview')) + GROUP BY day_start, breakdown_value_1) + GROUP BY day_start, breakdown_value_1 + ORDER BY day_start ASC, breakdown_value ASC) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC) + WHERE arrayExists(x -> isNotNull(x), breakdown_value) + GROUP BY breakdown_value + ORDER BY if(has(breakdown_value, '$$_posthog_breakdown_other_$$'), 2, if(has(breakdown_value, '$$_posthog_breakdown_null_$$'), 1, 0)) ASC, arraySum(total) DESC, breakdown_value ASC + LIMIT 50000 SETTINGS readonly=2, max_execution_time=60, allow_experimental_object_type=1, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0, transform_null_in=1, optimize_min_equality_disjunction_chain_length=4294967295, allow_experimental_join_condition=1, use_hive_partitioning=0 + ''' +# --- # name: TestPersonsRevenueAnalyticsManagedViewsets.test_get_revenue_for_events ''' SELECT persons__revenue_analytics.revenue AS revenue, diff --git a/posthog/hogql/database/schema/test/base.py b/posthog/hogql/database/schema/test/base.py index fd8b9aaac729..2b54a60ee86e 100644 --- a/posthog/hogql/database/schema/test/base.py +++ b/posthog/hogql/database/schema/test/base.py @@ -13,8 +13,10 @@ from posthog.hogql.query import execute_hogql_query from posthog.temporal.data_imports.sources.stripe.constants import ( + CHARGE_RESOURCE_NAME as STRIPE_CHARGE_RESOURCE_NAME, CUSTOMER_RESOURCE_NAME as STRIPE_CUSTOMER_RESOURCE_NAME, INVOICE_RESOURCE_NAME as STRIPE_INVOICE_RESOURCE_NAME, + SUBSCRIPTION_RESOURCE_NAME as STRIPE_SUBSCRIPTION_RESOURCE_NAME, ) from products.data_warehouse.backend.models import ( @@ -25,13 +27,17 @@ from products.data_warehouse.backend.test.utils import create_data_warehouse_table_from_csv from products.data_warehouse.backend.types import DataWarehouseManagedViewSetKind from products.revenue_analytics.backend.hogql_queries.test.data.structure import ( + STRIPE_CHARGE_COLUMNS, STRIPE_CUSTOMER_COLUMNS, STRIPE_INVOICE_COLUMNS, + STRIPE_SUBSCRIPTION_COLUMNS, ) TEST_BUCKET_BASE = "test_storage_bucket" INVOICES_TEST_BUCKET = f"{TEST_BUCKET_BASE}-posthog.revenue_analytics.insights_query_runner.stripe_invoices" CUSTOMERS_TEST_BUCKET = f"{TEST_BUCKET_BASE}-posthog.revenue_analytics.insights_query_runner.stripe_customers" +SUBSCRIPTIONS_TEST_BUCKET = f"{TEST_BUCKET_BASE}-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions" +CHARGES_TEST_BUCKET = f"{TEST_BUCKET_BASE}-posthog.revenue_analytics.insights_query_runner.stripe_charges" _TEST_DATA_DIR = ( Path(__file__).resolve().parents[5] / "products" @@ -53,54 +59,57 @@ class RevenueAnalyticsTestBase(ClickhouseTestMixin, BaseTest): PERSON_ID = "00000000-0000-0000-0000-000000000000" DISTINCT_ID = "distinct_id" + _TABLE_CONFIGS: dict[str, tuple[str, dict, str, str]] = { + "invoice": ("stripe_invoices", STRIPE_INVOICE_COLUMNS, INVOICES_TEST_BUCKET, STRIPE_INVOICE_RESOURCE_NAME), + "customer": ("stripe_customers", STRIPE_CUSTOMER_COLUMNS, CUSTOMERS_TEST_BUCKET, STRIPE_CUSTOMER_RESOURCE_NAME), + "subscription": ( + "stripe_subscriptions", + STRIPE_SUBSCRIPTION_COLUMNS, + SUBSCRIPTIONS_TEST_BUCKET, + STRIPE_SUBSCRIPTION_RESOURCE_NAME, + ), + "charge": ("stripe_charges", STRIPE_CHARGE_COLUMNS, CHARGES_TEST_BUCKET, STRIPE_CHARGE_RESOURCE_NAME), + } + def tearDown(self): - if hasattr(self, "invoices_cleanup_filesystem"): - self.invoices_cleanup_filesystem() - if hasattr(self, "customers_cleanup_filesystem"): - self.customers_cleanup_filesystem() + for cleanup in getattr(self, "_source_cleanups", []): + cleanup() super().tearDown() - def create_sources(self): - invoices_csv_path = _TEST_DATA_DIR / "stripe_invoices.csv" - invoices_table, self.source, credential, _, self.invoices_cleanup_filesystem = ( - create_data_warehouse_table_from_csv( - invoices_csv_path, - "stripe_invoice", - STRIPE_INVOICE_COLUMNS, - INVOICES_TEST_BUCKET, - self.team, - ) - ) + def create_source_table(self, key: str) -> None: + csv_name, columns, bucket, schema_name = self._TABLE_CONFIGS[key] - customers_csv_path = _TEST_DATA_DIR / "stripe_customers.csv" - customers_table, _, _, _, self.customers_cleanup_filesystem = create_data_warehouse_table_from_csv( - customers_csv_path, - "stripe_customer", - STRIPE_CUSTOMER_COLUMNS, - CUSTOMERS_TEST_BUCKET, + table, source, credential, _, cleanup = create_data_warehouse_table_from_csv( + _TEST_DATA_DIR / f"{csv_name}.csv", + f"stripe_{key}", + columns, + bucket, self.team, - source=self.source, - credential=credential, + source=getattr(self, "source", None), + credential=getattr(self, "_credential", None), ) - _invoices_schema = ExternalDataSchema.objects.create( - team=self.team, - name=STRIPE_INVOICE_RESOURCE_NAME, - source=self.source, - table=invoices_table, - should_sync=True, - last_synced_at="2024-01-01", - ) + if not hasattr(self, "source"): + self.source = source + self._credential = credential - _customers_schema = ExternalDataSchema.objects.create( + if not hasattr(self, "_source_cleanups"): + self._source_cleanups = [] + self._source_cleanups.append(cleanup) + + ExternalDataSchema.objects.create( team=self.team, - name=STRIPE_CUSTOMER_RESOURCE_NAME, + name=schema_name, source=self.source, - table=customers_table, + table=table, should_sync=True, last_synced_at="2024-01-01", ) + def create_sources(self): + self.create_source_table("invoice") + self.create_source_table("customer") + class RevenueAnalyticsManagedViewsetsTestMixin(RevenueAnalyticsTestBase): def setUp(self) -> None: diff --git a/products/data_warehouse/backend/data_load/test/test_source_templates.py b/products/data_warehouse/backend/data_load/test/test_source_templates.py index 9e38a6e4144b..860fb1237376 100644 --- a/products/data_warehouse/backend/data_load/test/test_source_templates.py +++ b/products/data_warehouse/backend/data_load/test/test_source_templates.py @@ -1,8 +1,15 @@ import pytest -from posthog.test.base import BaseTest +from freezegun import freeze_time +from posthog.test.base import BaseTest, _create_person from parameterized import parameterized +from posthog.schema import CurrencyCode + +from posthog.hogql.database.schema.test.base import RevenueAnalyticsTestBase +from posthog.hogql.parser import parse_select +from posthog.hogql.query import execute_hogql_query + from products.data_warehouse.backend.data_load.source_templates import _revenue_view_name, database_operations from products.data_warehouse.backend.models.join import DataWarehouseJoin @@ -92,3 +99,37 @@ def test_recreates_after_soft_delete(self): assert DataWarehouseJoin.objects.filter( team=self.team, joining_table_name="stripe_customer", deleted=True ).exists() + + +class TestCustomerRevenueViewPersonsJoin(RevenueAnalyticsTestBase): + """Verify that the joins created by database_operations actually resolve + when revenue analytics queries through them.""" + + def setUp(self): + super().setUp() + self.create_sources() + self.team.base_currency = CurrencyCode.GBP.value + self.team.save() + self.view_name = _revenue_view_name(self.source.prefix or "") + + def test_persons_join_resolves_on_customer_view(self): + _create_person( + team_id=self.team.pk, + distinct_ids=["person_cus_1"], + properties={"marker": "found"}, + ) + + database_operations(self.team.pk, self.source.prefix or "") + + with freeze_time(self.QUERY_TIMESTAMP): + response = execute_hogql_query( + parse_select( + f"SELECT id, persons.properties.marker FROM {self.view_name}" + f" WHERE persons.properties.marker IS NOT NULL ORDER BY id" + ), + self.team, + modifiers=self.MODIFIERS, + ) + assert len(response.results) == 1 + assert response.results[0][0] == "cus_1" + assert response.results[0][1] == "found" diff --git a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_gross_revenue_query_runner.ambr b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_gross_revenue_query_runner.ambr index 71f31a451e3a..f69fe09ec38d 100644 --- a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_gross_revenue_query_runner.ambr +++ b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_gross_revenue_query_runner.ambr @@ -546,28 +546,67 @@ FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge WHERE and(or(isNull(invoice_id), empty(invoice_id)), equals(posthog_test_stripe_charge.status, 'succeeded'))) AS revenue_analytics_revenue_item LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_subscription.customer AS customer_id, + JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('subscription', '::', ifNull(toString(posthog_test_stripe_subscription.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription + WHERE notEquals(JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) WHERE and(and(ifNull(greaterOrEquals(revenue_analytics_revenue_item.timestamp, assumeNotNull(toDateTime('2024-11-30 00:00:00', 'UTC'))), 0), ifNull(lessOrEquals(revenue_analytics_revenue_item.timestamp, assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), 0)), equals(revenue_analytics_customer.country, 'US')) GROUP BY breakdown_by, period_start @@ -1072,28 +1111,67 @@ FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge WHERE and(or(isNull(invoice_id), empty(invoice_id)), equals(posthog_test_stripe_charge.status, 'succeeded'))) AS revenue_analytics_revenue_item LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_subscription.customer AS customer_id, + JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('subscription', '::', ifNull(toString(posthog_test_stripe_subscription.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription + WHERE notEquals(JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) LEFT JOIN (SELECT posthog_test_stripe_product.id AS id, 'stripe.posthog_test' AS source_label, diff --git a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_metrics_query_runner.ambr b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_metrics_query_runner.ambr index d29c2d4fdbba..1f2f8d5c00b6 100644 --- a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_metrics_query_runner.ambr +++ b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_metrics_query_runner.ambr @@ -456,641 +456,130 @@ # --- # name: TestRevenueAnalyticsMetricsQueryRunner.test_with_country_filter ''' - SELECT subquery.breakdown_by AS breakdown_by, - subquery.period_start AS period_start, - sum(subquery.subscription_count) AS subscription_count, - sum(subquery.new_subscription_count) AS new_subscription_count, - sum(subquery.churned_subscription_count) AS churned_subscription_count, - countIf(subquery.customer_id, - ifNull(greaterOrEquals(subquery.subscription_count, - 1), 0)) AS customer_count, - countIf(subquery.customer_id, - subquery.is_new_customer) AS new_customer_count, - countIf(subquery.customer_id, - subquery.is_churned_customer) AS churned_customer_count, - ifNull(accurateCastOrNull(if(or(isNull(customer_count), ifNull(equals(customer_count, - 0), 0)), 0, - divide(sum(subquery.revenue), customer_count)), 'Decimal64(10)'), accurateCastOrNull(0, - 'Decimal64(10)')) AS arpu, - multiIf(ifNull(equals(customer_count, - 0), 0), accurateCastOrNull(0, - 'Decimal64(10)'), ifNull(equals(churned_customer_count, - 0), 0), NULL, - divideDecimal(arpu, - accurateCastOrNull(divide(churned_customer_count, - customer_count), 'Decimal64(10)'))) AS ltv + SELECT subquery.breakdown_by AS breakdown_by, subquery.period_start AS period_start, sum(subquery.subscription_count) AS subscription_count, sum(subquery.new_subscription_count) AS new_subscription_count, sum(subquery.churned_subscription_count) AS churned_subscription_count, countIf(subquery.customer_id, ifNull(greaterOrEquals(subquery.subscription_count, 1), 0)) AS customer_count, countIf(subquery.customer_id, subquery.is_new_customer) AS new_customer_count, countIf(subquery.customer_id, subquery.is_churned_customer) AS churned_customer_count, ifNull(accurateCastOrNull(if(or(isNull(customer_count), ifNull(equals(customer_count, 0), 0)), 0, divide(sum(subquery.revenue), customer_count)), 'Decimal64(10)'), accurateCastOrNull(0, 'Decimal64(10)')) AS arpu, multiIf(ifNull(equals(customer_count, 0), 0), accurateCastOrNull(0, 'Decimal64(10)'), ifNull(equals(churned_customer_count, 0), 0), NULL, divideDecimal(arpu, accurateCastOrNull(divide(churned_customer_count, customer_count), 'Decimal64(10)'))) AS ltv FROM ( - SELECT revenue_analytics_subscription.source_label AS breakdown_by, - revenue_analytics_subscription.customer_id AS customer_id, - toStartOfMonth(parseDateTime64BestEffortOrNull(arrayJoin(['2024-11-01 00:00:00', '2024-12-01 00:00:00', '2025-01-01 00:00:00', '2025-02-01 00:00:00', '2025-03-01 00:00:00', '2025-04-01 00:00:00', '2025-05-01 00:00:00']), 6, - 'UTC')) AS period_start, - countIf(DISTINCT revenue_analytics_subscription.id, - and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC')), period_start), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), period_start), 0)))) AS subscription_count, - countIf(DISTINCT revenue_analytics_subscription.id, - and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC')), date_add(period_start, - toIntervalMonth(-1))), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), date_add(period_start, - toIntervalMonth(-1))), 0)))) AS prev_subscription_count, - countIf(DISTINCT revenue_analytics_subscription.id, - ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC')), period_start), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC'))) - and isNull(period_start))) AS new_subscription_count, - countIf(DISTINCT revenue_analytics_subscription.id, - ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), date_add(period_start, - toIntervalMonth(-1))), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC'))) - and isNull(date_add(period_start, - toIntervalMonth(-1))))) AS churned_subscription_count, - and(ifNull(equals(prev_subscription_count, - 0), 0), ifNull(greater(subscription_count, - 0), 0)) AS is_new_customer, - and(ifNull(greater(churned_subscription_count, - 0), 0), ifNull(equals(churned_subscription_count, - prev_subscription_count), isNull(churned_subscription_count) - and isNull(prev_subscription_count))) AS is_churned_customer, - sumIf(revenue_analytics_revenue_item.amount, - ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_revenue_item.timestamp, - 'UTC')), period_start), isNull(toStartOfMonth(toTimeZone(revenue_analytics_revenue_item.timestamp, - 'UTC'))) + SELECT revenue_analytics_subscription.source_label AS breakdown_by, revenue_analytics_subscription.customer_id AS customer_id, toStartOfMonth(parseDateTime64BestEffortOrNull(arrayJoin(['2024-11-01 00:00:00', '2024-12-01 00:00:00', '2025-01-01 00:00:00', '2025-02-01 00:00:00', '2025-03-01 00:00:00', '2025-04-01 00:00:00', '2025-05-01 00:00:00']), 6, 'UTC')) AS period_start, countIf(DISTINCT revenue_analytics_subscription.id, and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC')), period_start), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), period_start), 0)))) AS subscription_count, countIf(DISTINCT revenue_analytics_subscription.id, and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC')), date_add(period_start, toIntervalMonth(-1))), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), date_add(period_start, toIntervalMonth(-1))), 0)))) AS prev_subscription_count, countIf(DISTINCT revenue_analytics_subscription.id, ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC')), period_start), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC'))) + and isNull(period_start))) AS new_subscription_count, countIf(DISTINCT revenue_analytics_subscription.id, ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), date_add(period_start, toIntervalMonth(-1))), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC'))) + and isNull(date_add(period_start, toIntervalMonth(-1))))) AS churned_subscription_count, and(ifNull(equals(prev_subscription_count, 0), 0), ifNull(greater(subscription_count, 0), 0)) AS is_new_customer, and(ifNull(greater(churned_subscription_count, 0), 0), ifNull(equals(churned_subscription_count, prev_subscription_count), isNull(churned_subscription_count) + and isNull(prev_subscription_count))) AS is_churned_customer, sumIf(revenue_analytics_revenue_item.amount, ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_revenue_item.timestamp, 'UTC')), period_start), isNull(toStartOfMonth(toTimeZone(revenue_analytics_revenue_item.timestamp, 'UTC'))) and isNull(period_start))) AS revenue FROM ( - SELECT subscription_id AS id, - 'revenue_analytics.events.purchase' AS source_label, - NULL AS plan_id, - product_id AS product_id, - toString(person_id) AS customer_id, - NULL AS status, - min_timestamp AS started_at, - if(ifNull(greater(max_timestamp_plus_dropoff_days, - today()), 0), NULL, - max_timestamp) AS ended_at, - NULL AS metadata + SELECT subscription_id AS id, 'revenue_analytics.events.purchase' AS source_label, NULL AS plan_id, product_id AS product_id, toString(person_id) AS customer_id, NULL AS status, min_timestamp AS started_at, if(ifNull(greater(max_timestamp_plus_dropoff_days, today()), 0), NULL, max_timestamp) AS ended_at, NULL AS metadata FROM ( - SELECT events__person.id AS person_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'subscription'), ''), 'null'), '^"|"$', - '') AS subscription_id, - min(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'product'), ''), 'null'), '^"|"$', - '')) AS product_id, - min(toTimeZone(events.timestamp, - 'UTC')) AS min_timestamp, - max(toTimeZone(events.timestamp, - 'UTC')) AS max_timestamp, - addDays(max_timestamp, - 45.0) AS max_timestamp_plus_dropoff_days + SELECT events__person.id AS person_id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription'), ''), 'null'), '^"|"$', '') AS subscription_id, min(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'product'), ''), 'null'), '^"|"$', '')) AS product_id, min(toTimeZone(events.timestamp, 'UTC')) AS min_timestamp, max(toTimeZone(events.timestamp, 'UTC')) AS max_timestamp, addDays(max_timestamp, 45.0) AS max_timestamp_plus_dropoff_days FROM events LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) + WHERE equals(person_distinct_id_overrides.team_id, 99999) GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, - events__override.distinct_id) + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) LEFT JOIN ( SELECT person.id AS id FROM person - WHERE equals(person.team_id, - 99999) + WHERE equals(person.team_id, 99999) GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, - 'UTC')), person.version), 1), plus(now64(6, - 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, - events.person_id), events__person.id) - WHERE and(equals(events.team_id, - 99999), and(1, - isNotNull(subscription_id))) - GROUP BY subscription_id, - person_id) + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) + WHERE and(equals(events.team_id, 99999), and(1, isNotNull(subscription_id))) + GROUP BY subscription_id, person_id) ORDER BY started_at DESC) AS revenue_analytics_subscription LEFT JOIN ( - SELECT toString(events.uuid) AS id, - toString(events.uuid) AS invoice_item_id, - 'revenue_analytics.events.purchase' AS source_label, - toTimeZone(events.timestamp, - 'UTC') AS timestamp, - timestamp AS created_at, - isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'subscription'), ''), 'null'), '^"|"$', - '')) AS is_recurring, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'product'), ''), 'null'), '^"|"$', - '') AS product_id, - toString(if(not(empty(events__override.distinct_id)), events__override.person_id, - events.person_id)) AS customer_id, - events.`$group_0` AS group_0_key, - events.`$group_1` AS group_1_key, - events.`$group_2` AS group_2_key, - events.`$group_3` AS group_3_key, - events.`$group_4` AS group_4_key, - NULL AS invoice_id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'subscription'), ''), 'null'), '^"|"$', - '') AS subscription_id, - toString(events.`$session_id`) AS session_id, - events.event AS event_name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'coupon'), ''), 'null'), '^"|"$', - '') AS coupon, - coupon AS coupon_id, - upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'currency'), ''), 'null'), '^"|"$', - '')) AS original_currency, - accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'revenue'), ''), 'null'), '^"|"$', - ''), 'Decimal64(10)') AS original_amount, - 1 AS enable_currency_aware_divider, - if(enable_currency_aware_divider, - accurateCastOrNull(1, - 'Decimal64(10)'), accurateCastOrNull(100, - 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, - currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - if(isNull(upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'currency'), ''), 'null'), '^"|"$', - ''))), accurateCastOrNull(currency_aware_amount, - 'Decimal64(10)'), if(equals(upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'currency'), ''), 'null'), '^"|"$', - '')), 'GBP'), toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'currency'), ''), 'null'), '^"|"$', - '')), toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)) = 0, - toDecimal64(0, - 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'currency'), ''), 'null'), '^"|"$', - '')), toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)) = 0, - toDecimal64(1, - 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, - 'currency'), ''), 'null'), '^"|"$', - '')), toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - 'GBP', - toDate(toTimeZone(events.timestamp, - 'UTC')), toDecimal64(0, - 10)))))) AS amount + SELECT toString(events.uuid) AS id, toString(events.uuid) AS invoice_item_id, 'revenue_analytics.events.purchase' AS source_label, toTimeZone(events.timestamp, 'UTC') AS timestamp, timestamp AS created_at, isNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription'), ''), 'null'), '^"|"$', '')) AS is_recurring, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'product'), ''), 'null'), '^"|"$', '') AS product_id, toString(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id)) AS customer_id, events.`$group_0` AS group_0_key, events.`$group_1` AS group_1_key, events.`$group_2` AS group_2_key, events.`$group_3` AS group_3_key, events.`$group_4` AS group_4_key, NULL AS invoice_id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'subscription'), ''), 'null'), '^"|"$', '') AS subscription_id, toString(events.`$session_id`) AS session_id, events.event AS event_name, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'coupon'), ''), 'null'), '^"|"$', '') AS coupon, coupon AS coupon_id, upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'currency'), ''), 'null'), '^"|"$', '')) AS original_currency, accurateCastOrNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'revenue'), ''), 'null'), '^"|"$', ''), 'Decimal64(10)') AS original_amount, 1 AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'GBP' AS currency, if(isNull(upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'currency'), ''), 'null'), '^"|"$', ''))), accurateCastOrNull(currency_aware_amount, 'Decimal64(10)'), if(equals(upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'currency'), ''), 'null'), '^"|"$', '')), 'GBP'), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'currency'), ''), 'null'), '^"|"$', '')), toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'currency'), ''), 'null'), '^"|"$', '')), toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', upper(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(events.properties, 'currency'), ''), 'null'), '^"|"$', '')), toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', 'GBP', toDate(toTimeZone(events.timestamp, 'UTC')), toDecimal64(0, 10)))))) AS amount FROM events LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) + WHERE equals(person_distinct_id_overrides.team_id, 99999) GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, - events__override.distinct_id) - WHERE and(equals(events.team_id, - 99999), and(equals(events.event, - 'purchase'), 1, - isNotNull(amount))) - ORDER BY timestamp DESC) AS revenue_analytics_revenue_item ON equals(revenue_analytics_subscription.id, - revenue_analytics_revenue_item.subscription_id) + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) + WHERE and(equals(events.team_id, 99999), and(equals(events.event, 'purchase'), 1, isNotNull(amount))) + ORDER BY timestamp DESC) AS revenue_analytics_revenue_item ON equals(revenue_analytics_subscription.id, revenue_analytics_revenue_item.subscription_id) LEFT JOIN ( - SELECT toString(persons.id) AS id, - 'revenue_analytics.events.purchase' AS source_label, - persons.created_at AS timestamp, - persons.properties___name AS name, - persons.properties___email AS email, - persons.properties___phone AS phone, - persons.properties___address AS address, - persons.properties___metadata AS metadata, - persons.`properties___$geoip_country_name` AS country, - formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, - NULL AS initial_coupon, - NULL AS initial_coupon_id + SELECT toString(persons.id) AS id, 'revenue_analytics.events.purchase' AS source_label, persons.created_at AS timestamp, persons.properties___name AS name, persons.properties___email AS email, persons.properties___phone AS phone, persons.properties___address AS address, persons.properties___metadata AS metadata, persons.`properties___$geoip_country_name` AS country, formatDateTime(toStartOfMonth(persons.created_at), '%Y-%m') AS cohort, NULL AS initial_coupon, NULL AS initial_coupon_id FROM ( - SELECT person.id AS id, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'name'), ''), 'null'), '^"|"$', - '') AS properties___name, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'email'), ''), 'null'), '^"|"$', - '') AS properties___email, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'phone'), ''), 'null'), '^"|"$', - '') AS properties___phone, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'address'), ''), 'null'), '^"|"$', - '') AS properties___address, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - 'metadata'), ''), 'null'), '^"|"$', - '') AS properties___metadata, - replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, - '$geoip_country_name'), ''), 'null'), '^"|"$', - '') AS `properties___$geoip_country_name`, - toTimeZone(person.created_at, - 'UTC') AS created_at + SELECT person.id AS id, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'name'), ''), 'null'), '^"|"$', '') AS properties___name, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'email'), ''), 'null'), '^"|"$', '') AS properties___email, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'phone'), ''), 'null'), '^"|"$', '') AS properties___phone, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'address'), ''), 'null'), '^"|"$', '') AS properties___address, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, 'metadata'), ''), 'null'), '^"|"$', '') AS properties___metadata, replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(person.properties, '$geoip_country_name'), ''), 'null'), '^"|"$', '') AS `properties___$geoip_country_name`, toTimeZone(person.created_at, 'UTC') AS created_at FROM person - WHERE and(equals(person.team_id, - 99999), in(tuple(person.id, - person.version), ( - SELECT person.id AS id, - max(person.version) AS version - FROM person WHERE equals(person.team_id, - 99999) + WHERE and(equals(person.team_id, 99999), in(tuple(person.id, person.version), ( + SELECT person.id AS id, max(person.version) AS version + FROM person WHERE equals(person.team_id, 99999) GROUP BY person.id - HAVING and(ifNull(equals(argMax(person.is_deleted, - person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, - 'UTC'), person.version), plus(now64(6, - 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons + HAVING and(ifNull(equals(argMax(person.is_deleted, person.version), 0), 0), ifNull(less(argMax(toTimeZone(person.created_at, 'UTC'), person.version), plus(now64(6, 'UTC'), toIntervalDay(1))), 0))))) SETTINGS optimize_aggregation_in_order=1) AS persons INNER JOIN ( SELECT DISTINCT events__person.id AS person_id FROM events LEFT OUTER JOIN ( - SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, - person_distinct_id_overrides.distinct_id AS distinct_id + SELECT tupleElement(argMax(tuple(person_distinct_id_overrides.person_id), person_distinct_id_overrides.version), 1) AS person_id, person_distinct_id_overrides.distinct_id AS distinct_id FROM person_distinct_id_overrides - WHERE equals(person_distinct_id_overrides.team_id, - 99999) + WHERE equals(person_distinct_id_overrides.team_id, 99999) GROUP BY person_distinct_id_overrides.distinct_id - HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, - events__override.distinct_id) + HAVING ifNull(equals(tupleElement(argMax(tuple(person_distinct_id_overrides.is_deleted), person_distinct_id_overrides.version), 1), 0), 0) SETTINGS optimize_aggregation_in_order=1) AS events__override ON equals(events.distinct_id, events__override.distinct_id) LEFT JOIN ( SELECT person.id AS id FROM person - WHERE equals(person.team_id, - 99999) + WHERE equals(person.team_id, 99999) GROUP BY person.id - HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, - 'UTC')), person.version), 1), plus(now64(6, - 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, - events.person_id), events__person.id) - WHERE equals(events.team_id, - 99999)) AS events ON equals(persons.id, - events.person_id) - ORDER BY persons.created_at DESC) AS revenue_analytics_customer ON equals(revenue_analytics_subscription.customer_id, - revenue_analytics_customer.id) - WHERE equals(revenue_analytics_customer.country, - 'US') - GROUP BY revenue_analytics_subscription.customer_id, - breakdown_by, - period_start - ORDER BY revenue_analytics_subscription.customer_id ASC, - breakdown_by ASC, - period_start ASC) AS subquery - GROUP BY subquery.breakdown_by, - subquery.period_start - ORDER BY subquery.breakdown_by ASC, - subquery.period_start ASC, - subscription_count DESC, - customer_count DESC + HAVING and(ifNull(equals(tupleElement(argMax(tuple(person.is_deleted), person.version), 1), 0), 0), ifNull(less(tupleElement(argMax(tuple(toTimeZone(person.created_at, 'UTC')), person.version), 1), plus(now64(6, 'UTC'), toIntervalDay(1))), 0)) SETTINGS optimize_aggregation_in_order=1) AS events__person ON equals(if(not(empty(events__override.distinct_id)), events__override.person_id, events.person_id), events__person.id) + WHERE equals(events.team_id, 99999)) AS events ON equals(persons.id, events.person_id) + ORDER BY persons.created_at DESC) AS revenue_analytics_customer ON equals(revenue_analytics_subscription.customer_id, revenue_analytics_customer.id) + WHERE equals(revenue_analytics_customer.country, 'US') + GROUP BY revenue_analytics_subscription.customer_id, breakdown_by, period_start + ORDER BY revenue_analytics_subscription.customer_id ASC, breakdown_by ASC, period_start ASC) AS subquery + GROUP BY subquery.breakdown_by, subquery.period_start + ORDER BY subquery.breakdown_by ASC, subquery.period_start ASC, subscription_count DESC, customer_count DESC LIMIT 10000 UNION ALL - SELECT subquery.breakdown_by AS breakdown_by, - subquery.period_start AS period_start, - sum(subquery.subscription_count) AS subscription_count, - sum(subquery.new_subscription_count) AS new_subscription_count, - sum(subquery.churned_subscription_count) AS churned_subscription_count, - countIf(subquery.customer_id, - ifNull(greaterOrEquals(subquery.subscription_count, - 1), 0)) AS customer_count, - countIf(subquery.customer_id, - subquery.is_new_customer) AS new_customer_count, - countIf(subquery.customer_id, - subquery.is_churned_customer) AS churned_customer_count, - ifNull(accurateCastOrNull(if(or(isNull(customer_count), ifNull(equals(customer_count, - 0), 0)), 0, - divide(sum(subquery.revenue), customer_count)), 'Decimal64(10)'), accurateCastOrNull(0, - 'Decimal64(10)')) AS arpu, - multiIf(ifNull(equals(customer_count, - 0), 0), accurateCastOrNull(0, - 'Decimal64(10)'), ifNull(equals(churned_customer_count, - 0), 0), NULL, - divideDecimal(arpu, - accurateCastOrNull(divide(churned_customer_count, - customer_count), 'Decimal64(10)'))) AS ltv + SELECT subquery.breakdown_by AS breakdown_by, subquery.period_start AS period_start, sum(subquery.subscription_count) AS subscription_count, sum(subquery.new_subscription_count) AS new_subscription_count, sum(subquery.churned_subscription_count) AS churned_subscription_count, countIf(subquery.customer_id, ifNull(greaterOrEquals(subquery.subscription_count, 1), 0)) AS customer_count, countIf(subquery.customer_id, subquery.is_new_customer) AS new_customer_count, countIf(subquery.customer_id, subquery.is_churned_customer) AS churned_customer_count, ifNull(accurateCastOrNull(if(or(isNull(customer_count), ifNull(equals(customer_count, 0), 0)), 0, divide(sum(subquery.revenue), customer_count)), 'Decimal64(10)'), accurateCastOrNull(0, 'Decimal64(10)')) AS arpu, multiIf(ifNull(equals(customer_count, 0), 0), accurateCastOrNull(0, 'Decimal64(10)'), ifNull(equals(churned_customer_count, 0), 0), NULL, divideDecimal(arpu, accurateCastOrNull(divide(churned_customer_count, customer_count), 'Decimal64(10)'))) AS ltv FROM ( - SELECT revenue_analytics_subscription.source_label AS breakdown_by, - revenue_analytics_subscription.customer_id AS customer_id, - toStartOfMonth(parseDateTime64BestEffortOrNull(arrayJoin(['2024-11-01 00:00:00', '2024-12-01 00:00:00', '2025-01-01 00:00:00', '2025-02-01 00:00:00', '2025-03-01 00:00:00', '2025-04-01 00:00:00', '2025-05-01 00:00:00']), 6, - 'UTC')) AS period_start, - countIf(DISTINCT revenue_analytics_subscription.id, - and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC')), period_start), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), period_start), 0)))) AS subscription_count, - countIf(DISTINCT revenue_analytics_subscription.id, - and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC')), date_add(period_start, - toIntervalMonth(-1))), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), date_add(period_start, - toIntervalMonth(-1))), 0)))) AS prev_subscription_count, - countIf(DISTINCT revenue_analytics_subscription.id, - ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC')), period_start), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, - 'UTC'))) - and isNull(period_start))) AS new_subscription_count, - countIf(DISTINCT revenue_analytics_subscription.id, - ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC')), date_add(period_start, - toIntervalMonth(-1))), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, - 'UTC'))) - and isNull(date_add(period_start, - toIntervalMonth(-1))))) AS churned_subscription_count, - and(ifNull(equals(prev_subscription_count, - 0), 0), ifNull(greater(subscription_count, - 0), 0)) AS is_new_customer, - and(ifNull(greater(churned_subscription_count, - 0), 0), ifNull(equals(churned_subscription_count, - prev_subscription_count), isNull(churned_subscription_count) - and isNull(prev_subscription_count))) AS is_churned_customer, - sumIf(revenue_analytics_revenue_item.amount, - ifNull(equals(toStartOfMonth(revenue_analytics_revenue_item.timestamp), period_start), isNull(toStartOfMonth(revenue_analytics_revenue_item.timestamp)) + SELECT revenue_analytics_subscription.source_label AS breakdown_by, revenue_analytics_subscription.customer_id AS customer_id, toStartOfMonth(parseDateTime64BestEffortOrNull(arrayJoin(['2024-11-01 00:00:00', '2024-12-01 00:00:00', '2025-01-01 00:00:00', '2025-02-01 00:00:00', '2025-03-01 00:00:00', '2025-04-01 00:00:00', '2025-05-01 00:00:00']), 6, 'UTC')) AS period_start, countIf(DISTINCT revenue_analytics_subscription.id, and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC')), period_start), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), period_start), 0)))) AS subscription_count, countIf(DISTINCT revenue_analytics_subscription.id, and(ifNull(lessOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC')), date_add(period_start, toIntervalMonth(-1))), 0), or(isNull(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), ifNull(greaterOrEquals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), date_add(period_start, toIntervalMonth(-1))), 0)))) AS prev_subscription_count, countIf(DISTINCT revenue_analytics_subscription.id, ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC')), period_start), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.started_at, 'UTC'))) + and isNull(period_start))) AS new_subscription_count, countIf(DISTINCT revenue_analytics_subscription.id, ifNull(equals(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC')), date_add(period_start, toIntervalMonth(-1))), isNull(toStartOfMonth(toTimeZone(revenue_analytics_subscription.ended_at, 'UTC'))) + and isNull(date_add(period_start, toIntervalMonth(-1))))) AS churned_subscription_count, and(ifNull(equals(prev_subscription_count, 0), 0), ifNull(greater(subscription_count, 0), 0)) AS is_new_customer, and(ifNull(greater(churned_subscription_count, 0), 0), ifNull(equals(churned_subscription_count, prev_subscription_count), isNull(churned_subscription_count) + and isNull(prev_subscription_count))) AS is_churned_customer, sumIf(revenue_analytics_revenue_item.amount, ifNull(equals(toStartOfMonth(revenue_analytics_revenue_item.timestamp), period_start), isNull(toStartOfMonth(revenue_analytics_revenue_item.timestamp)) and isNull(period_start))) AS revenue FROM ( - SELECT posthog_test_stripe_subscription.id AS id, - 'stripe.posthog_test' AS source_label, - JSONExtractString(posthog_test_stripe_subscription.plan, - 'id') AS plan_id, - JSONExtractString(posthog_test_stripe_subscription.plan, - 'product') AS product_id, - posthog_test_stripe_subscription.customer AS customer_id, - posthog_test_stripe_subscription.status AS status, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, - 'UTC') AS started_at, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.ended_at), 6, - 'UTC') AS ended_at, - posthog_test_stripe_subscription.metadata AS metadata - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', - 'object_storage_root_user', - 'object_storage_root_password', - 'CSVWithNames', - '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription) AS revenue_analytics_subscription + SELECT posthog_test_stripe_subscription.id AS id, 'stripe.posthog_test' AS source_label, JSONExtractString(posthog_test_stripe_subscription.plan, 'id') AS plan_id, JSONExtractString(posthog_test_stripe_subscription.plan, 'product') AS product_id, posthog_test_stripe_subscription.customer AS customer_id, posthog_test_stripe_subscription.status AS status, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, 'UTC') AS started_at, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.ended_at), 6, 'UTC') AS ended_at, posthog_test_stripe_subscription.metadata AS metadata + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription) AS revenue_analytics_subscription LEFT JOIN ( - SELECT if(ifNull(greater(invoice.period_months, - 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', - ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, - invoice.invoice_item_id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - addMonths(invoice.timestamp, - invoice.month_index) AS timestamp, - invoice.created_at AS created_at, - ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, - invoice.product_id AS product_id, - invoice.customer_id AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - invoice.id AS invoice_id, - invoice.subscription_id AS subscription_id, - NULL AS session_id, - NULL AS event_name, - JSONExtractString(invoice.discount, - 'coupon', - 'name') AS coupon, - JSONExtractString(invoice.discount, - 'coupon', - 'id') AS coupon_id, - upper(invoice.currency) AS original_currency, - accurateCastOrNull(invoice.amount_captured, - 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, - accurateCastOrNull(1, - 'Decimal64(10)'), accurateCastOrNull(100, - 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, - currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - divideDecimal(if(equals(original_currency, - currency), toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - original_currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10)) = 0, - toDecimal64(0, - 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - original_currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10)) = 0, - toDecimal64(1, - 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - original_currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10))))), accurateCastOrNull(invoice.period_months, - 'Decimal64(10)')) AS amount + SELECT if(ifNull(greater(invoice.period_months, 1), 0), concat(ifNull(toString(invoice.invoice_item_id), ''), '_', ifNull(toString(invoice.month_index), '')), invoice.invoice_item_id) AS id, invoice.invoice_item_id AS invoice_item_id, 'stripe.posthog_test' AS source_label, addMonths(invoice.timestamp, invoice.month_index) AS timestamp, invoice.created_at AS created_at, ifNull(notEmpty(invoice.subscription_id), 0) AS is_recurring, invoice.product_id AS product_id, invoice.customer_id AS customer_id, NULL AS group_0_key, NULL AS group_1_key, NULL AS group_2_key, NULL AS group_3_key, NULL AS group_4_key, invoice.id AS invoice_id, invoice.subscription_id AS subscription_id, NULL AS session_id, NULL AS event_name, JSONExtractString(invoice.discount, 'coupon', 'name') AS coupon, JSONExtractString(invoice.discount, 'coupon', 'id') AS coupon_id, upper(invoice.currency) AS original_currency, accurateCastOrNull(invoice.amount_captured, 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'GBP' AS currency, divideDecimal(if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))), accurateCastOrNull(invoice.period_months, 'Decimal64(10)')) AS amount FROM ( - SELECT posthog_test_stripe_invoice.id AS id, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, - 'UTC') AS created_at, - posthog_test_stripe_invoice.customer AS customer_id, - posthog_test_stripe_invoice.subscription AS subscription_id, - posthog_test_stripe_invoice.discount AS discount, - arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, - 'data'), ''), 'null'), '^"|"$', - '')))) AS data, - JSONExtractString(data, - 'id') AS invoice_item_id, - JSONExtractUInt(data, - 'amount') AS amount_before_discount, - coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, - 'amount'), JSONExtractArrayRaw(data, - 'discount_amounts'))), 0) AS discount_amount, - greatest(minus(amount_before_discount, - discount_amount), 0) AS amount_captured, - JSONExtractString(data, - 'currency') AS currency, - JSONExtractString(data, - 'price', - 'product') AS product_id, - fromUnixTimestamp(JSONExtractUInt(data, - 'period', - 'start')) AS period_start, - fromUnixTimestamp(JSONExtractUInt(data, - 'period', - 'end')) AS period_end, - greatest(toInt16(round(divide(dateDiff('day', - ifNull(period_start, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, - 'UTC')), ifNull(period_end, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, - 'UTC'))), 30.44))), 1) AS period_months, - arrayJoin(range(0, - period_months)) AS month_index, - ifNull(period_start, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, - 'UTC')) AS timestamp - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', - 'object_storage_root_user', - 'object_storage_root_password', - 'CSVWithNames', - '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + SELECT posthog_test_stripe_invoice.id AS id, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at, posthog_test_stripe_invoice.customer AS customer_id, posthog_test_stripe_invoice.subscription AS subscription_id, posthog_test_stripe_invoice.discount AS discount, arrayJoin(JSONExtractArrayRaw(assumeNotNull(replaceRegexpAll(nullIf(nullIf(JSONExtractRaw(posthog_test_stripe_invoice.lines, 'data'), ''), 'null'), '^"|"$', '')))) AS data, JSONExtractString(data, 'id') AS invoice_item_id, JSONExtractUInt(data, 'amount') AS amount_before_discount, coalesce(arraySum(arrayMap(x -> JSONExtractInt(x, 'amount'), JSONExtractArrayRaw(data, 'discount_amounts'))), 0) AS discount_amount, greatest(minus(amount_before_discount, discount_amount), 0) AS amount_captured, JSONExtractString(data, 'currency') AS currency, JSONExtractString(data, 'price', 'product') AS product_id, fromUnixTimestamp(JSONExtractUInt(data, 'period', 'start')) AS period_start, fromUnixTimestamp(JSONExtractUInt(data, 'period', 'end')) AS period_end, greatest(toInt16(round(divide(dateDiff('day', ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')), ifNull(period_end, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC'))), 30.44))), 1) AS period_months, arrayJoin(range(0, period_months)) AS month_index, ifNull(period_start, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC')) AS timestamp + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice WHERE posthog_test_stripe_invoice.paid) AS invoice UNION ALL - SELECT posthog_test_stripe_charge.id AS id, - id AS invoice_item_id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, - 'UTC') AS timestamp, - parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, - 'UTC') AS created_at, - 0 AS is_recurring, - NULL AS product_id, - posthog_test_stripe_charge.customer AS customer_id, - NULL AS group_0_key, - NULL AS group_1_key, - NULL AS group_2_key, - NULL AS group_3_key, - NULL AS group_4_key, - posthog_test_stripe_charge.invoice AS invoice_id, - NULL AS subscription_id, - NULL AS session_id, - NULL AS event_name, - NULL AS coupon, - NULL AS coupon_id, - upper(posthog_test_stripe_charge.currency) AS original_currency, - accurateCastOrNull(posthog_test_stripe_charge.amount_captured, - 'Decimal64(10)') AS original_amount, - in(original_currency, - ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, - if(enable_currency_aware_divider, - accurateCastOrNull(1, - 'Decimal64(10)'), accurateCastOrNull(100, - 'Decimal64(10)')) AS currency_aware_divider, - divideDecimal(original_amount, - currency_aware_divider) AS currency_aware_amount, - 'GBP' AS currency, - if(equals(original_currency, - currency), toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - original_currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10)) = 0, - toDecimal64(0, - 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, - 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - original_currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10)) = 0, - toDecimal64(1, - 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - original_currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, - 'rate', - currency, - toDate(ifNull(timestamp, toDateTime(0, - 'UTC'))), toDecimal64(0, - 10))))) AS amount - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', - 'object_storage_root_user', - 'object_storage_root_password', - 'CSVWithNames', - '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge - WHERE and(or(isNull(invoice_id), empty(invoice_id)), equals(posthog_test_stripe_charge.status, - 'succeeded'))) AS revenue_analytics_revenue_item ON equals(revenue_analytics_subscription.id, - revenue_analytics_revenue_item.subscription_id) + SELECT posthog_test_stripe_charge.id AS id, id AS invoice_item_id, 'stripe.posthog_test' AS source_label, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS timestamp, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at, 0 AS is_recurring, NULL AS product_id, posthog_test_stripe_charge.customer AS customer_id, NULL AS group_0_key, NULL AS group_1_key, NULL AS group_2_key, NULL AS group_3_key, NULL AS group_4_key, posthog_test_stripe_charge.invoice AS invoice_id, NULL AS subscription_id, NULL AS session_id, NULL AS event_name, NULL AS coupon, NULL AS coupon_id, upper(posthog_test_stripe_charge.currency) AS original_currency, accurateCastOrNull(posthog_test_stripe_charge.amount_captured, 'Decimal64(10)') AS original_amount, in(original_currency, ['BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF']) AS enable_currency_aware_divider, if(enable_currency_aware_divider, accurateCastOrNull(1, 'Decimal64(10)'), accurateCastOrNull(100, 'Decimal64(10)')) AS currency_aware_divider, divideDecimal(original_amount, currency_aware_divider) AS currency_aware_amount, 'GBP' AS currency, if(equals(original_currency, currency), toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(0, 10), multiplyDecimal(divideDecimal(toDecimal64(currency_aware_amount, 10), if(dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)) = 0, toDecimal64(1, 10), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', original_currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10)))), dictGetOrDefault(`posthog_test`.`exchange_rate_dict`, 'rate', currency, toDate(ifNull(timestamp, toDateTime(0, 'UTC'))), toDecimal64(0, 10))))) AS amount + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE and(or(isNull(invoice_id), empty(invoice_id)), equals(posthog_test_stripe_charge.status, 'succeeded'))) AS revenue_analytics_revenue_item ON equals(revenue_analytics_subscription.id, revenue_analytics_revenue_item.subscription_id) LEFT JOIN ( - SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, - 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, - 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + SELECT inner.id AS id, inner.source_label AS source_label, inner.timestamp AS timestamp, inner.name AS name, inner.email AS email, inner.phone AS phone, inner.address AS address, if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, inner.country AS country, inner.cohort AS cohort, inner.initial_coupon AS initial_coupon, inner.initial_coupon_id AS initial_coupon_id + FROM ( + SELECT outer.id AS id, 'stripe.posthog_test' AS source_label, parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, outer.name AS name, outer.email AS email, outer.phone AS phone, outer.address AS address, outer.metadata AS metadata, JSONExtractString(address, 'country') AS country, cohort_inner.cohort AS cohort, cohort_inner.initial_coupon AS initial_coupon, cohort_inner.initial_coupon_id AS initial_coupon_id, ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, ifNull(resolved.resolved_source, '') AS resolved_source FROM ( SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', - 'object_storage_root_user', - 'object_storage_root_password', - 'CSVWithNames', - '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer LEFT JOIN ( - SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, - 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, - 'coupon', - 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, - 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, - 'coupon', - 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, - 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', - 'object_storage_root_user', - 'object_storage_root_password', - 'CSVWithNames', - '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, - outer.id)) AS revenue_analytics_customer ON equals(revenue_analytics_subscription.customer_id, - revenue_analytics_customer.id) - WHERE equals(revenue_analytics_customer.country, - 'US') - GROUP BY revenue_analytics_subscription.customer_id, - breakdown_by, - period_start - ORDER BY revenue_analytics_subscription.customer_id ASC, - breakdown_by ASC, - period_start ASC) AS subquery - GROUP BY subquery.breakdown_by, - subquery.period_start - ORDER BY subquery.breakdown_by ASC, - subquery.period_start ASC, - subscription_count DESC, - customer_count DESC - LIMIT 10000 SETTINGS format_csv_allow_double_quotes=1, - readonly=2, - max_execution_time=60, - allow_experimental_object_type=1, - max_ast_elements=4000000, - max_expanded_ast_elements=4000000, - max_bytes_before_external_group_by=0, - transform_null_in=1, - optimize_min_equality_disjunction_chain_length=4294967295, - allow_experimental_join_condition=1, - use_hive_partitioning=0 + SELECT invoice.customer AS customer_id, formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN ( + SELECT child_meta.customer_id AS customer_id, argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM ( + SELECT posthog_test_stripe_subscription.customer AS customer_id, JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('subscription', '::', ifNull(toString(posthog_test_stripe_subscription.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription + WHERE notEquals(JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id'), '') + UNION ALL + SELECT posthog_test_stripe_charge.customer AS customer_id, JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL + SELECT posthog_test_stripe_invoice.customer AS customer_id, JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(revenue_analytics_subscription.customer_id, revenue_analytics_customer.id) + WHERE equals(revenue_analytics_customer.country, 'US') + GROUP BY revenue_analytics_subscription.customer_id, breakdown_by, period_start + ORDER BY revenue_analytics_subscription.customer_id ASC, breakdown_by ASC, period_start ASC) AS subquery + GROUP BY subquery.breakdown_by, subquery.period_start + ORDER BY subquery.breakdown_by ASC, subquery.period_start ASC, subscription_count DESC, customer_count DESC + LIMIT 10000 SETTINGS format_csv_allow_double_quotes=1, readonly=2, max_execution_time=60, allow_experimental_object_type=1, max_ast_elements=4000000, max_expanded_ast_elements=4000000, max_bytes_before_external_group_by=0, transform_null_in=1, optimize_min_equality_disjunction_chain_length=4294967295, allow_experimental_join_condition=1, use_hive_partitioning=0 ''' # --- # name: TestRevenueAnalyticsMetricsQueryRunner.test_with_data diff --git a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_mrr_query_runner.ambr b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_mrr_query_runner.ambr index 6fe2f368f798..048500302909 100644 --- a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_mrr_query_runner.ambr +++ b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_mrr_query_runner.ambr @@ -329,14 +329,31 @@ FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription) AS subscription WHERE and(greaterOrEquals(toTimeZone(subscription.ended_at, 'UTC'), addDays(assumeNotNull(toDateTime('2024-11-30 00:00:00', 'UTC')), -60)), lessOrEquals(toTimeZone(subscription.ended_at, 'UTC'), assumeNotNull(toDateTime('2025-05-31 23:59:59', 'UTC'))))) AS revenue_analytics_revenue_item LEFT JOIN ( - SELECT outer.id AS id, 'stripe.posthog_test' AS source_label, parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, outer.name AS name, outer.email AS email, outer.phone AS phone, outer.address AS address, outer.metadata AS metadata, JSONExtractString(address, 'country') AS country, cohort_inner.cohort AS cohort, cohort_inner.initial_coupon AS initial_coupon, cohort_inner.initial_coupon_id AS initial_coupon_id + SELECT inner.id AS id, inner.source_label AS source_label, inner.timestamp AS timestamp, inner.name AS name, inner.email AS email, inner.phone AS phone, inner.address AS address, if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, inner.country AS country, inner.cohort AS cohort, inner.initial_coupon AS initial_coupon, inner.initial_coupon_id AS initial_coupon_id + FROM ( + SELECT outer.id AS id, 'stripe.posthog_test' AS source_label, parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, outer.name AS name, outer.email AS email, outer.phone AS phone, outer.address AS address, outer.metadata AS metadata, JSONExtractString(address, 'country') AS country, cohort_inner.cohort AS cohort, cohort_inner.initial_coupon AS initial_coupon, cohort_inner.initial_coupon_id AS initial_coupon_id, ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, ifNull(resolved.resolved_source, '') AS resolved_source FROM ( SELECT * FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer LEFT JOIN ( SELECT invoice.customer AS customer_id, formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN ( + SELECT child_meta.customer_id AS customer_id, argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM ( + SELECT posthog_test_stripe_subscription.customer AS customer_id, JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('subscription', '::', ifNull(toString(posthog_test_stripe_subscription.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription + WHERE notEquals(JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id'), '') + UNION ALL + SELECT posthog_test_stripe_charge.customer AS customer_id, JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL + SELECT posthog_test_stripe_invoice.customer AS customer_id, JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) WHERE and(and(ifNull(greaterOrEquals(revenue_analytics_revenue_item.timestamp, addDays(assumeNotNull(toDateTime('2024-11-30 00:00:00', 'UTC')), -60)), 0), ifNull(lessOrEquals(revenue_analytics_revenue_item.timestamp, assumeNotNull(toDateTime('2025-05-31 23:59:59', 'UTC'))), 0)), ifNull(equals(revenue_analytics_revenue_item.is_recurring, 1), 0), equals(revenue_analytics_customer.country, 'US'))) AS subquery GROUP BY breakdown_by, customer_id, subscription_id, day) AS grouped_by_day GROUP BY breakdown_by, customer_id, subscription_id) AS map_query) AS mrr_per_day_subquery @@ -690,14 +707,31 @@ FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription) AS subscription WHERE and(greaterOrEquals(toTimeZone(subscription.ended_at, 'UTC'), addDays(assumeNotNull(toDateTime('2024-11-30 00:00:00', 'UTC')), -60)), lessOrEquals(toTimeZone(subscription.ended_at, 'UTC'), assumeNotNull(toDateTime('2025-05-31 23:59:59', 'UTC'))))) AS revenue_analytics_revenue_item LEFT JOIN ( - SELECT outer.id AS id, 'stripe.posthog_test' AS source_label, parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, outer.name AS name, outer.email AS email, outer.phone AS phone, outer.address AS address, outer.metadata AS metadata, JSONExtractString(address, 'country') AS country, cohort_inner.cohort AS cohort, cohort_inner.initial_coupon AS initial_coupon, cohort_inner.initial_coupon_id AS initial_coupon_id + SELECT inner.id AS id, inner.source_label AS source_label, inner.timestamp AS timestamp, inner.name AS name, inner.email AS email, inner.phone AS phone, inner.address AS address, if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, inner.country AS country, inner.cohort AS cohort, inner.initial_coupon AS initial_coupon, inner.initial_coupon_id AS initial_coupon_id + FROM ( + SELECT outer.id AS id, 'stripe.posthog_test' AS source_label, parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, outer.name AS name, outer.email AS email, outer.phone AS phone, outer.address AS address, outer.metadata AS metadata, JSONExtractString(address, 'country') AS country, cohort_inner.cohort AS cohort, cohort_inner.initial_coupon AS initial_coupon, cohort_inner.initial_coupon_id AS initial_coupon_id, ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, ifNull(resolved.resolved_source, '') AS resolved_source FROM ( SELECT * FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer LEFT JOIN ( SELECT invoice.customer AS customer_id, formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN ( + SELECT child_meta.customer_id AS customer_id, argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM ( + SELECT posthog_test_stripe_subscription.customer AS customer_id, JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('subscription', '::', ifNull(toString(posthog_test_stripe_subscription.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_subscription.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_subscriptions/posthog_test_stripe_subscription/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `plan` String, `status` String, `created` DateTime, `customer` String, `ended_at` DateTime, `metadata` String') AS posthog_test_stripe_subscription + WHERE notEquals(JSONExtractString(posthog_test_stripe_subscription.metadata, 'posthog_person_distinct_id'), '') + UNION ALL + SELECT posthog_test_stripe_charge.customer AS customer_id, JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL + SELECT posthog_test_stripe_invoice.customer AS customer_id, JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) LEFT JOIN ( SELECT posthog_test_stripe_product.id AS id, 'stripe.posthog_test' AS source_label, posthog_test_stripe_product.name AS name FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.insights_query_runner.stripe_products/posthog_test_stripe_product/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `type` String, `active` UInt8, `images` String, `object` String, `created` DateTime, `features` String, `livemode` UInt8, `metadata` String, `tax_code` String, `attributes` String, `updated_at` DateTime, `description` String, `default_price_id` String') AS posthog_test_stripe_product) AS revenue_analytics_product ON equals(revenue_analytics_revenue_item.product_id, revenue_analytics_product.id) diff --git a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_overview_query_runner.ambr b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_overview_query_runner.ambr index a01da8c4b641..e91cd49c958a 100644 --- a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_overview_query_runner.ambr +++ b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_overview_query_runner.ambr @@ -1552,28 +1552,61 @@ FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge WHERE and(or(isNull(invoice_id), empty(invoice_id)), equals(posthog_test_stripe_charge.status, 'succeeded'))) AS revenue_analytics_revenue_item LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.overview_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(revenue_analytics_revenue_item.customer_id, revenue_analytics_customer.id) WHERE and(and(ifNull(greaterOrEquals(revenue_analytics_revenue_item.timestamp, assumeNotNull(toDateTime('2025-04-30 00:00:00', 'UTC'))), 0), ifNull(lessOrEquals(revenue_analytics_revenue_item.timestamp, assumeNotNull(toDateTime('2025-05-30 23:59:59', 'UTC'))), 0)), ifNull(greater(revenue_analytics_revenue_item.amount, accurateCastOrNull(0, 'Decimal64(10)')), 0), equals(revenue_analytics_customer.country, 'US'))) LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, readonly=2, diff --git a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_top_customers_query_runner.ambr b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_top_customers_query_runner.ambr index 0e66b3efd0f5..0ecde8fdc011 100644 --- a/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_top_customers_query_runner.ambr +++ b/products/revenue_analytics/backend/hogql_queries/test/__snapshots__/test_revenue_analytics_top_customers_query_runner.ambr @@ -366,28 +366,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, @@ -597,28 +630,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, @@ -828,28 +894,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, @@ -1061,28 +1160,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) GROUP BY customer_id, name ORDER BY amount DESC @@ -1294,28 +1426,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, @@ -1525,28 +1690,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, @@ -1757,28 +1955,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, @@ -1988,28 +2219,61 @@ ORDER BY amount DESC LIMIT 20 BY month) AS inner LEFT JOIN - (SELECT outer.id AS id, - 'stripe.posthog_test' AS source_label, - parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, - outer.name AS name, - outer.email AS email, - outer.phone AS phone, - outer.address AS address, - outer.metadata AS metadata, - JSONExtractString(address, 'country') AS country, - cohort_inner.cohort AS cohort, - cohort_inner.initial_coupon AS initial_coupon, - cohort_inner.initial_coupon_id AS initial_coupon_id + (SELECT inner.id AS id, + inner.source_label AS source_label, + inner.timestamp AS timestamp, + inner.name AS name, + inner.email AS email, + inner.phone AS phone, + inner.address AS address, + if(notEquals(JSONExtractString(inner.metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(ifNull(notEquals(inner.resolved_distinct_id, ''), 1), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(inner.metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(inner.metadata, '{}'), k), JSONExtractKeys(ifNull(inner.metadata, '{}')))), map('posthog_person_distinct_id', inner.resolved_distinct_id, 'posthog_person_distinct_id_source', inner.resolved_source))), inner.metadata)) AS metadata, + inner.country AS country, + inner.cohort AS cohort, + inner.initial_coupon AS initial_coupon, + inner.initial_coupon_id AS initial_coupon_id FROM - (SELECT * - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer - LEFT JOIN - (SELECT invoice.customer AS customer_id, - formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, - argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, - argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id - FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice - GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id)) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) + (SELECT outer.id AS id, + 'stripe.posthog_test' AS source_label, + parseDateTime64BestEffortOrNull(toString(outer.created), 6, 'UTC') AS timestamp, + outer.name AS name, + outer.email AS email, + outer.phone AS phone, + outer.address AS address, + outer.metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort_inner.cohort AS cohort, + cohort_inner.initial_coupon AS initial_coupon, + cohort_inner.initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM + (SELECT * + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_customers/posthog_test_stripe_customer/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `name` String, `email` String, `phone` String, `address` String, `created` DateTime, `metadata` String')) AS outer + LEFT JOIN + (SELECT invoice.customer AS customer_id, + formatDateTime(toStartOfMonth(min(parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC'))), '%Y-%m') AS cohort, + argMin(JSONExtractString(invoice.discount, 'coupon', 'name'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon, + argMin(JSONExtractString(invoice.discount, 'coupon', 'id'), parseDateTime64BestEffortOrNull(toString(invoice.created), 6, 'UTC')) AS initial_coupon_id + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS invoice + GROUP BY invoice.customer) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT child_meta.customer_id AS customer_id, + argMax(child_meta.distinct_id, child_meta.created_at) AS resolved_distinct_id, + argMax(child_meta.source_ref, child_meta.created_at) AS resolved_source + FROM + (SELECT posthog_test_stripe_charge.customer AS customer_id, + JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', ifNull(toString(posthog_test_stripe_charge.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_charge.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_charges/posthog_test_stripe_charge/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `paid` Int8, `amount` Int64, `object` String, `source` String, `status` String, `created` DateTime, `invoice` String, `outcome` String, `captured` Int8, `currency` String, `customer` String, `disputed` Int8, `livemode` Int8, `metadata` String, `refunded` Int8, `description` String, `receipt_url` String, `failure_code` String, `fraud_details` String, `radar_options` String, `receipt_email` String, `payment_intent` String, `payment_method` String, `amount_captured` Int64, `amount_refunded` Int64, `billing_details` String, `failure_message` String, `balance_transaction` String, `statement_descriptor` String, `payment_method_details` String, `calculated_statement_descriptor` String') AS posthog_test_stripe_charge + WHERE notEquals(JSONExtractString(posthog_test_stripe_charge.metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT posthog_test_stripe_invoice.customer AS customer_id, + JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', ifNull(toString(posthog_test_stripe_invoice.id), '')) AS source_ref, + parseDateTime64BestEffortOrNull(toString(posthog_test_stripe_invoice.created), 6, 'UTC') AS created_at + FROM s3('http://host.docker.internal:19000/posthog/test_storage_bucket-posthog.revenue_analytics.top_customers_query_runner.stripe_invoices/posthog_test_stripe_invoice/*.csv', 'object_storage_root_user', 'object_storage_root_password', 'CSVWithNames', '`id` String, `tax` Int64, `paid` UInt8, `lines` String, `total` Int64, `charge` String, `issuer` String, `number` String, `object` String, `status` String, `created` DateTime, `currency` String, `customer` String, `discount` String, `due_date` DateTime, `livemode` UInt8, `metadata` String, `subtotal` Int64, `attempted` UInt8, `discounts` String, `rendering` String, `amount_due` Int64, `amount_paid` Int64, `description` String, `invoice_pdf` String, `account_name` String, `auto_advance` UInt8, `effective_at` DateTime, `subscription` String, `attempt_count` UInt8, `automatic_tax` String, `customer_name` String, `period_end_at` DateTime, `billing_reason` String, `customer_email` String, `ending_balance` Int64, `payment_intent` String, `account_country` String, `amount_shipping` Int64, `period_start_at` DateTime, `amount_remaining` Int64, `customer_address` String, `customer_tax_ids` String, `paid_out_of_band` UInt8, `payment_settings` String, `starting_balance` Int64, `collection_method` String, `default_tax_rates` String, `total_tax_amounts` String, `hosted_invoice_url` String, `status_transitions` String, `customer_tax_exempt` String, `total_excluding_tax` Int64, `subscription_details` String, `webhooks_delivered_at` DateTime, `subtotal_excluding_tax` Int64, `total_discount_amounts` String, `pre_payment_credit_notes_amount` Int64, `post_payment_credit_notes_amount` Int64') AS posthog_test_stripe_invoice + WHERE notEquals(JSONExtractString(posthog_test_stripe_invoice.metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY child_meta.customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner) AS revenue_analytics_customer ON equals(inner.customer_id, revenue_analytics_customer.id) ORDER BY amount DESC LIMIT 20 BY month LIMIT 100 SETTINGS format_csv_allow_double_quotes=1, diff --git a/products/revenue_analytics/backend/views/sources/constants.py b/products/revenue_analytics/backend/views/sources/constants.py new file mode 100644 index 000000000000..c4c0005c2249 --- /dev/null +++ b/products/revenue_analytics/backend/views/sources/constants.py @@ -0,0 +1,2 @@ +POSTHOG_PERSON_DISTINCT_ID_METADATA_KEY = "posthog_person_distinct_id" +POSTHOG_PERSON_DISTINCT_ID_SOURCE_METADATA_KEY = "posthog_person_distinct_id_source" diff --git a/products/revenue_analytics/backend/views/sources/stripe/customer.py b/products/revenue_analytics/backend/views/sources/stripe/customer.py index 069b1b09cd24..4a9f04abc3de 100644 --- a/products/revenue_analytics/backend/views/sources/stripe/customer.py +++ b/products/revenue_analytics/backend/views/sources/stripe/customer.py @@ -1,18 +1,56 @@ from typing import cast +from django.db.models import QuerySet + from posthog.hogql import ast +from posthog.hogql.ast import SelectQuery +from posthog.hogql.parser import parse_expr, parse_select from posthog.temporal.data_imports.sources.stripe.constants import ( + CHARGE_RESOURCE_NAME as STRIPE_CHARGE_RESOURCE_NAME, CUSTOMER_RESOURCE_NAME as STRIPE_CUSTOMER_RESOURCE_NAME, INVOICE_RESOURCE_NAME as STRIPE_INVOICE_RESOURCE_NAME, + SUBSCRIPTION_RESOURCE_NAME as STRIPE_SUBSCRIPTION_RESOURCE_NAME, ) from products.data_warehouse.backend.models.external_data_schema import ExternalDataSchema from products.data_warehouse.backend.models.table import DataWarehouseTable from products.revenue_analytics.backend.views.core import BuiltQuery, SourceHandle, view_prefix_for_source from products.revenue_analytics.backend.views.schemas.customer import SCHEMA +from products.revenue_analytics.backend.views.sources.constants import ( + POSTHOG_PERSON_DISTINCT_ID_METADATA_KEY, + POSTHOG_PERSON_DISTINCT_ID_SOURCE_METADATA_KEY, +) from products.revenue_analytics.backend.views.sources.helpers import extract_json_string, get_cohort_expr +_METADATA_TO_MAP_EXPR = ( + "mapFromArrays(" + "JSONExtractKeys(ifNull(metadata, '{}')), " + "arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))" + ")" +) + +_ENRICHED_METADATA_EXPR = parse_expr( + f""" + if( + JSONExtractString(metadata, {{distinct_id_key}}) != '', + toJSONString(mapUpdate({_METADATA_TO_MAP_EXPR}, map({{source_key}}, 'customer'))), + if( + resolved_distinct_id != '', + toJSONString(mapUpdate({_METADATA_TO_MAP_EXPR}, map( + {{distinct_id_key}}, resolved_distinct_id, + {{source_key}}, resolved_source + ))), + metadata + ) + ) + """, + placeholders={ + "distinct_id_key": ast.Constant(value=POSTHOG_PERSON_DISTINCT_ID_METADATA_KEY), + "source_key": ast.Constant(value=POSTHOG_PERSON_DISTINCT_ID_SOURCE_METADATA_KEY), + }, +) + def build(handle: SourceHandle) -> BuiltQuery: source = handle.source @@ -21,13 +59,12 @@ def build(handle: SourceHandle) -> BuiltQuery: prefix = view_prefix_for_source(source) - # Get all schemas for the source, avoid calling `filter` and do the filtering on Python-land - # to avoid n+1 queries + # Get all schemas for the source, avoid calling `filter` and do the filtering on Python-land to avoid n+1 queries schemas = source.schemas.all() customer_schema = next((schema for schema in schemas if schema.name == STRIPE_CUSTOMER_RESOURCE_NAME), None) if customer_schema is None: return BuiltQuery( - key=str(source.id), # Using source rather than table because table hasn't been found yet + key=str(source.id), prefix=prefix, query=ast.SelectQuery.empty(columns=SCHEMA.fields), test_comments="no_schema", @@ -42,21 +79,16 @@ def build(handle: SourceHandle) -> BuiltQuery: test_comments="no_table", ) - invoice_schema = next((schema for schema in schemas if schema.name == STRIPE_INVOICE_RESOURCE_NAME), None) - invoice_table = None - if invoice_schema is not None: - invoice_schema = cast(ExternalDataSchema, invoice_schema) - invoice_table = invoice_schema.table - if invoice_table is not None: - invoice_table = cast(DataWarehouseTable, invoice_table) - - table = cast(DataWarehouseTable, customer_schema.table) + customer_table = cast(DataWarehouseTable, customer_schema.table) + invoice_table = _get_table(schemas, STRIPE_INVOICE_RESOURCE_NAME) + subscription_table = _get_table(schemas, STRIPE_SUBSCRIPTION_RESOURCE_NAME) + charge_table = _get_table(schemas, STRIPE_CHARGE_RESOURCE_NAME) query = ast.SelectQuery( select=[ ast.Alias(alias="id", expr=ast.Field(chain=["outer", "id"])), ast.Alias(alias="source_label", expr=ast.Constant(value=prefix)), - ast.Alias(alias="timestamp", expr=ast.Field(chain=["created_at"])), + ast.Alias(alias="timestamp", expr=ast.Field(chain=["outer", "created_at"])), ast.Alias(alias="name", expr=ast.Field(chain=["name"])), ast.Alias(alias="email", expr=ast.Field(chain=["email"])), ast.Alias(alias="phone", expr=ast.Field(chain=["phone"])), @@ -72,12 +104,13 @@ def build(handle: SourceHandle) -> BuiltQuery: ], select_from=ast.JoinExpr( alias="outer", - table=ast.Field(chain=[table.name]), + table=ast.Field(chain=[customer_table.name]), ), ) # If there's an invoice table we can generate the cohort entry - # by looking at the first invoice for each customer + # by looking at the first invoice for each customer. + # Cohort is the month of a customer's first invoice if invoice_table is not None: cohort_alias: ast.Alias | None = next( (alias for alias in query.select if isinstance(alias, ast.Alias) and alias.alias == "cohort"), None @@ -143,4 +176,136 @@ def build(handle: SourceHandle) -> BuiltQuery: ), ) - return BuiltQuery(key=str(table.id), prefix=prefix, query=query) + child_tables: list[tuple[str, DataWarehouseTable]] = [] + if subscription_table is not None: + child_tables.append(("subscription", subscription_table)) + if charge_table is not None: + child_tables.append(("charge", charge_table)) + if invoice_table is not None: + child_tables.append(("invoice", invoice_table)) + + if child_tables: + query = _build_resolved_distinct_id_query(child_tables=child_tables, query=query) + + return BuiltQuery(key=str(customer_table.id), prefix=prefix, query=query) + + +def _get_table(schemas: QuerySet[ExternalDataSchema], schema_name: str) -> DataWarehouseTable | None: + schema = next((schema for schema in schemas if schema.name == schema_name), None) + if schema is None: + return None + + table = schema.table + if table is not None: + table = cast(DataWarehouseTable, table) + + return table + + +def _build_resolved_distinct_id_query( + child_tables: list[tuple[str, DataWarehouseTable]], query: SelectQuery +) -> SelectQuery: + resolved_subquery = _build_resolved_subquery(child_tables) + + last_join = query.select_from + if last_join is not None: + while last_join.next_join is not None: + last_join = last_join.next_join + last_join.next_join = ast.JoinExpr( + alias="resolved", + table=resolved_subquery, + join_type="LEFT JOIN", + constraint=ast.JoinConstraint( + constraint_type="ON", + expr=ast.CompareOperation( + left=ast.Field(chain=["resolved", "customer_id"]), + right=ast.Field(chain=["outer", "id"]), + op=ast.CompareOperationOp.Eq, + ), + ), + ) + + query.select.append( + ast.Alias( + alias="resolved_distinct_id", + expr=ast.Call( + name="ifNull", args=[ast.Field(chain=["resolved", "resolved_distinct_id"]), ast.Constant(value="")] + ), + ), + ) + query.select.append( + ast.Alias( + alias="resolved_source", + expr=ast.Call( + name="ifNull", args=[ast.Field(chain=["resolved", "resolved_source"]), ast.Constant(value="")] + ), + ), + ) + + outer_query = ast.SelectQuery( + select=[ + ast.Alias(alias="id", expr=ast.Field(chain=["id"])), + ast.Alias(alias="source_label", expr=ast.Field(chain=["source_label"])), + ast.Alias(alias="timestamp", expr=ast.Field(chain=["timestamp"])), + ast.Alias(alias="name", expr=ast.Field(chain=["name"])), + ast.Alias(alias="email", expr=ast.Field(chain=["email"])), + ast.Alias(alias="phone", expr=ast.Field(chain=["phone"])), + ast.Alias(alias="address", expr=ast.Field(chain=["address"])), + ast.Alias(alias="metadata", expr=_ENRICHED_METADATA_EXPR), + ast.Alias(alias="country", expr=ast.Field(chain=["country"])), + ast.Alias(alias="cohort", expr=ast.Field(chain=["cohort"])), + ast.Alias(alias="initial_coupon", expr=ast.Field(chain=["initial_coupon"])), + ast.Alias(alias="initial_coupon_id", expr=ast.Field(chain=["initial_coupon_id"])), + ], + select_from=ast.JoinExpr(table=query, alias="inner"), + ) + + return outer_query + + +def _build_resolved_subquery(child_tables: list[tuple[str, DataWarehouseTable]]) -> ast.SelectQuery: + union_legs = [_build_child_union_leg(table.name, label) for label, table in child_tables] + + union_query: ast.SelectQuery | ast.SelectSetQuery = union_legs[0] + if len(union_legs) > 1: + union_query = ast.SelectSetQuery( + initial_select_query=union_legs[0], + subsequent_select_queries=[ + ast.SelectSetNode(select_query=leg, set_operator="UNION ALL") for leg in union_legs[1:] + ], + ) + + return ast.SelectQuery( + select=[ + ast.Field(chain=["customer_id"]), + ast.Alias( + alias="resolved_distinct_id", + expr=ast.Call(name="argMax", args=[ast.Field(chain=["distinct_id"]), ast.Field(chain=["created_at"])]), + ), + ast.Alias( + alias="resolved_source", + expr=ast.Call(name="argMax", args=[ast.Field(chain=["source_ref"]), ast.Field(chain=["created_at"])]), + ), + ], + select_from=ast.JoinExpr(table=union_query, alias="child_meta"), + group_by=[ast.Field(chain=["customer_id"])], + ) + + +def _build_child_union_leg(table_name: str, label: str) -> ast.SelectQuery | ast.SelectSetQuery: + # nosemgrep: hogql-fstring-audit (table_name is internal Stripe table name from system schema, not user input) + return parse_select( + f""" + SELECT + customer_id, + JSONExtractString(metadata, {{metadata_key}}) AS distinct_id, + concat({{label}}, '::', id) AS source_ref, + created_at + FROM {table_name} + WHERE JSONExtractString(metadata, {{metadata_key}}) != '' + """, + placeholders={ + "metadata_key": ast.Constant(value=POSTHOG_PERSON_DISTINCT_ID_METADATA_KEY), + "label": ast.Constant(value=label), + }, + ) diff --git a/products/revenue_analytics/backend/views/sources/test/stripe/__snapshots__/test_stripe_customer.ambr b/products/revenue_analytics/backend/views/sources/test/stripe/__snapshots__/test_stripe_customer.ambr index 52143cbe2a02..b77553a65678 100644 --- a/products/revenue_analytics/backend/views/sources/test/stripe/__snapshots__/test_stripe_customer.ambr +++ b/products/revenue_analytics/backend/views/sources/test/stripe/__snapshots__/test_stripe_customer.ambr @@ -1,33 +1,167 @@ # serializer version: 1 +# name: TestCustomerStripeBuilder.test_build_customer_query_with_all_schemas_for_metadata_resolution + ''' + SELECT id AS id, + source_label AS source_label, + timestamp AS timestamp, + name AS name, + email AS email, + phone AS phone, + address AS address, + if(notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(notEquals(resolved_distinct_id, ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))), map('posthog_person_distinct_id', resolved_distinct_id, 'posthog_person_distinct_id_source', resolved_source))), metadata)) AS metadata, + country AS country, + cohort AS cohort, + initial_coupon AS initial_coupon, + initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.stripe_test' AS source_label, + outer.created_at AS timestamp, + name AS name, + email AS email, + phone AS phone, + address AS address, + metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort AS cohort, + initial_coupon AS initial_coupon, + initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM stripe_test_customer AS outer + LEFT JOIN + (SELECT customer_id, + formatDateTime(toStartOfMonth(min(created_at)), '%Y-%m') AS cohort, + argMin(JSONExtractString(discount, 'coupon', 'name'), created_at) AS initial_coupon, + argMin(JSONExtractString(discount, 'coupon', 'id'), created_at) AS initial_coupon_id + FROM stripe_test_invoice AS invoice + GROUP BY customer_id) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT customer_id, + argMax(distinct_id, created_at) AS resolved_distinct_id, + argMax(source_ref, created_at) AS resolved_source + FROM + (SELECT customer_id, + JSONExtractString(metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('subscription', '::', id) AS source_ref, + created_at + FROM stripe_test_subscription + WHERE notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT customer_id, + JSONExtractString(metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('charge', '::', id) AS source_ref, + created_at + FROM stripe_test_charge + WHERE notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), '') + UNION ALL SELECT customer_id, + JSONExtractString(metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', id) AS source_ref, + created_at + FROM stripe_test_invoice + WHERE notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner + ''' +# --- # name: TestCustomerStripeBuilder.test_build_customer_query_with_customer_and_invoice_schemas ''' - SELECT outer.id AS id, - 'stripe.stripe_test' AS source_label, - created_at AS timestamp, + SELECT id AS id, + source_label AS source_label, + timestamp AS timestamp, name AS name, email AS email, phone AS phone, address AS address, - metadata AS metadata, - JSONExtractString(address, 'country') AS country, + if(notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(notEquals(resolved_distinct_id, ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))), map('posthog_person_distinct_id', resolved_distinct_id, 'posthog_person_distinct_id_source', resolved_source))), metadata)) AS metadata, + country AS country, cohort AS cohort, initial_coupon AS initial_coupon, initial_coupon_id AS initial_coupon_id - FROM stripe_test_customer AS outer - LEFT JOIN - (SELECT customer_id, - formatDateTime(toStartOfMonth(min(created_at)), '%Y-%m') AS cohort, - argMin(JSONExtractString(discount, 'coupon', 'name'), created_at) AS initial_coupon, - argMin(JSONExtractString(discount, 'coupon', 'id'), created_at) AS initial_coupon_id - FROM stripe_test_invoice AS invoice - GROUP BY customer_id) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + FROM + (SELECT outer.id AS id, + 'stripe.stripe_test' AS source_label, + outer.created_at AS timestamp, + name AS name, + email AS email, + phone AS phone, + address AS address, + metadata AS metadata, + JSONExtractString(address, 'country') AS country, + cohort AS cohort, + initial_coupon AS initial_coupon, + initial_coupon_id AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM stripe_test_customer AS outer + LEFT JOIN + (SELECT customer_id, + formatDateTime(toStartOfMonth(min(created_at)), '%Y-%m') AS cohort, + argMin(JSONExtractString(discount, 'coupon', 'name'), created_at) AS initial_coupon, + argMin(JSONExtractString(discount, 'coupon', 'id'), created_at) AS initial_coupon_id + FROM stripe_test_invoice AS invoice + GROUP BY customer_id) AS cohort_inner ON equals(cohort_inner.customer_id, outer.id) + LEFT JOIN + (SELECT customer_id, + argMax(distinct_id, created_at) AS resolved_distinct_id, + argMax(source_ref, created_at) AS resolved_source + FROM + (SELECT customer_id, + JSONExtractString(metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('invoice', '::', id) AS source_ref, + created_at + FROM stripe_test_invoice + WHERE notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner + ''' +# --- +# name: TestCustomerStripeBuilder.test_build_customer_query_with_customer_and_subscription_schemas + ''' + SELECT id AS id, + source_label AS source_label, + timestamp AS timestamp, + name AS name, + email AS email, + phone AS phone, + address AS address, + if(notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))), map('posthog_person_distinct_id_source', 'customer'))), if(notEquals(resolved_distinct_id, ''), toJSONString(mapUpdate(mapFromArrays(JSONExtractKeys(ifNull(metadata, '{}')), arrayMap(k -> JSONExtractString(ifNull(metadata, '{}'), k), JSONExtractKeys(ifNull(metadata, '{}')))), map('posthog_person_distinct_id', resolved_distinct_id, 'posthog_person_distinct_id_source', resolved_source))), metadata)) AS metadata, + country AS country, + cohort AS cohort, + initial_coupon AS initial_coupon, + initial_coupon_id AS initial_coupon_id + FROM + (SELECT outer.id AS id, + 'stripe.stripe_test' AS source_label, + outer.created_at AS timestamp, + name AS name, + email AS email, + phone AS phone, + address AS address, + metadata AS metadata, + JSONExtractString(address, 'country') AS country, + NULL AS cohort, + NULL AS initial_coupon, + NULL AS initial_coupon_id, + ifNull(resolved.resolved_distinct_id, '') AS resolved_distinct_id, + ifNull(resolved.resolved_source, '') AS resolved_source + FROM stripe_test_customer AS outer + LEFT JOIN + (SELECT customer_id, + argMax(distinct_id, created_at) AS resolved_distinct_id, + argMax(source_ref, created_at) AS resolved_source + FROM + (SELECT customer_id, + JSONExtractString(metadata, 'posthog_person_distinct_id') AS distinct_id, + concat('subscription', '::', id) AS source_ref, + created_at + FROM stripe_test_subscription + WHERE notEquals(JSONExtractString(metadata, 'posthog_person_distinct_id'), '')) AS child_meta + GROUP BY customer_id) AS resolved ON equals(resolved.customer_id, outer.id)) AS inner ''' # --- # name: TestCustomerStripeBuilder.test_build_customer_query_with_customer_schema ''' SELECT outer.id AS id, 'stripe.stripe_test' AS source_label, - created_at AS timestamp, + outer.created_at AS timestamp, name AS name, email AS email, phone AS phone, diff --git a/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer.py b/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer.py index bf04213dfefd..6e976945b06e 100644 --- a/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer.py +++ b/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer.py @@ -1,4 +1,19 @@ -from posthog.temporal.data_imports.sources.stripe.constants import CUSTOMER_RESOURCE_NAME, INVOICE_RESOURCE_NAME +import json + +from freezegun import freeze_time + +from posthog.schema import CurrencyCode + +from posthog.hogql.database.schema.test.base import RevenueAnalyticsTestBase +from posthog.hogql.parser import parse_select +from posthog.hogql.query import execute_hogql_query + +from posthog.temporal.data_imports.sources.stripe.constants import ( + CHARGE_RESOURCE_NAME, + CUSTOMER_RESOURCE_NAME, + INVOICE_RESOURCE_NAME, + SUBSCRIPTION_RESOURCE_NAME, +) from products.revenue_analytics.backend.views.schemas.customer import SCHEMA as CUSTOMER_SCHEMA from products.revenue_analytics.backend.views.sources.stripe.customer import build @@ -42,6 +57,20 @@ def test_build_customer_query_with_customer_and_invoice_schemas(self): query_sql = query.query.to_hogql() self.assertQueryMatchesSnapshot(query_sql, replace_all_numbers=True) + def test_build_customer_query_with_all_schemas_for_metadata_resolution(self): + self.setup_stripe_external_data_source( + schemas=[CUSTOMER_RESOURCE_NAME, INVOICE_RESOURCE_NAME, SUBSCRIPTION_RESOURCE_NAME, CHARGE_RESOURCE_NAME] + ) + customer_table = self.get_stripe_table_by_schema_name(CUSTOMER_RESOURCE_NAME) + + query = build(self.stripe_handle) + + self.assertQueryContainsFields(query.query, CUSTOMER_SCHEMA) + self.assertBuiltQueryStructure(query, str(customer_table.id), f"stripe.{self.external_data_source.prefix}") + + query_sql = query.query.to_hogql() + self.assertQueryMatchesSnapshot(query_sql, replace_all_numbers=True) + def test_build_with_no_customer_schema(self): """Test that build returns view even when no customer schema exists.""" # Setup without customer schema @@ -93,6 +122,18 @@ def test_build_with_no_source(self): with self.assertRaises(ValueError): build(handle) + def test_build_customer_query_with_customer_and_subscription_schemas(self): + self.setup_stripe_external_data_source(schemas=[CUSTOMER_RESOURCE_NAME, SUBSCRIPTION_RESOURCE_NAME]) + customer_table = self.get_stripe_table_by_schema_name(CUSTOMER_RESOURCE_NAME) + + query = build(self.stripe_handle) + + self.assertQueryContainsFields(query.query, CUSTOMER_SCHEMA) + self.assertBuiltQueryStructure(query, str(customer_table.id), f"stripe.{self.external_data_source.prefix}") + + query_sql = query.query.to_hogql() + self.assertQueryMatchesSnapshot(query_sql, replace_all_numbers=True) + def test_customer_query_contains_required_fields(self): """Test that the generated query contains all required customer fields.""" self.setup_stripe_external_data_source(schemas=[CUSTOMER_RESOURCE_NAME]) @@ -107,3 +148,61 @@ def test_customer_query_contains_required_fields(self): # Check that source_label contains the expected prefix expected_prefix = f"stripe.{self.external_data_source.prefix}" self.assertIn(f"'{expected_prefix}'", query_sql) + + +class TestCustomerStripeMetadataResolution(RevenueAnalyticsTestBase): + """Integration tests that assert the metadata coalescing values produced by the customer view builder""" + + def setUp(self): + super().setUp() + self.create_sources() + self.create_source_table("subscription") + self.create_source_table("charge") + self.team.base_currency = CurrencyCode.GBP.value + self.team.save() + self.view_name = f"stripe.posthog_test.{CUSTOMER_SCHEMA.source_suffix}" + + def _query_metadata(self) -> dict[str, dict]: + with freeze_time(self.QUERY_TIMESTAMP): + response = execute_hogql_query( + parse_select(f"SELECT id, metadata FROM {self.view_name} ORDER BY id"), + self.team, + modifiers=self.MODIFIERS, + ) + return {row[0]: json.loads(row[1]) for row in response.results} + + def test_metadata_resolution_from_customer(self): + """cus_1 has posthog_person_distinct_id set directly on the customer object.""" + results = self._query_metadata() + + self.assertEqual("person_cus_1", results["cus_1"]["posthog_person_distinct_id"]) + self.assertEqual("customer", results["cus_1"]["posthog_person_distinct_id_source"]) + + def test_metadata_resolution_from_subscription(self): + """cus_2 has no distinct_id on the customer, but sub_2 has it in metadata.""" + results = self._query_metadata() + + self.assertEqual("person_cus_2", results["cus_2"]["posthog_person_distinct_id"]) + self.assertEqual("subscription::sub_2", results["cus_2"]["posthog_person_distinct_id_source"]) + + def test_metadata_resolution_from_charge(self): + """cus_3 has no distinct_id on the customer, but ch_3 has it in metadata.""" + results = self._query_metadata() + + self.assertEqual("person_cus_3", results["cus_3"]["posthog_person_distinct_id"]) + self.assertEqual("charge::ch_3", results["cus_3"]["posthog_person_distinct_id_source"]) + + def test_no_metadata_when_absent_everywhere(self): + """cus_4 has no distinct_id on customer, subscriptions, or charges.""" + results = self._query_metadata() + + self.assertNotIn("posthog_person_distinct_id", results["cus_4"]) + self.assertNotIn("posthog_person_distinct_id_source", results["cus_4"]) + + def test_freshest_child_wins_across_types(self): + """cus_5 has distinct_id on both sub_5 (Feb 2025) and ch_15 (Mar 2025). + The charge is newer, so it should win.""" + results = self._query_metadata() + + self.assertEqual("person_cus_5_from_charge", results["cus_5"]["posthog_person_distinct_id"]) + self.assertEqual("charge::ch_15", results["cus_5"]["posthog_person_distinct_id_source"]) diff --git a/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer_metadata_resolution.py b/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer_metadata_resolution.py new file mode 100644 index 000000000000..5260e4146a22 --- /dev/null +++ b/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer_metadata_resolution.py @@ -0,0 +1,223 @@ +import tempfile +from pathlib import Path + +from freezegun import freeze_time +from posthog.test.base import APIBaseTest, ClickhouseTestMixin + +from posthog.schema import ( + CurrencyCode, + DateRange, + HogQLQueryModifiers, + RevenueAnalyticsTopCustomersGroupBy, + RevenueAnalyticsTopCustomersQuery, + RevenueAnalyticsTopCustomersQueryResponse, +) + +from posthog.temporal.data_imports.sources.stripe.constants import ( + CHARGE_RESOURCE_NAME as STRIPE_CHARGE_RESOURCE_NAME, + CUSTOMER_RESOURCE_NAME as STRIPE_CUSTOMER_RESOURCE_NAME, + INVOICE_RESOURCE_NAME as STRIPE_INVOICE_RESOURCE_NAME, + SUBSCRIPTION_RESOURCE_NAME as STRIPE_SUBSCRIPTION_RESOURCE_NAME, +) + +from products.data_warehouse.backend.models.external_data_schema import ExternalDataSchema +from products.data_warehouse.backend.test.utils import create_data_warehouse_table_from_csv +from products.revenue_analytics.backend.hogql_queries.revenue_analytics_top_customers_query_runner import ( + RevenueAnalyticsTopCustomersQueryRunner, +) +from products.revenue_analytics.backend.hogql_queries.test.data.structure import ( + STRIPE_CHARGE_COLUMNS, + STRIPE_INVOICE_COLUMNS, +) + + +def _nullable_columns(basic_types: dict[str, str]) -> dict[str, dict[str, str | bool]]: + from products.data_warehouse.backend.models import CLICKHOUSE_HOGQL_MAPPING + from products.data_warehouse.backend.models.util import clean_type + + return { + key: { + "hogql": CLICKHOUSE_HOGQL_MAPPING[clean_type(value)].__name__, + "clickhouse": f"Nullable({value})", + "valid": True, + } + for key, value in basic_types.items() + } + + +NULLABLE_STRIPE_CUSTOMER_COLUMNS = _nullable_columns( + { + "id": "String", + "created": "Int64", + "name": "String", + "email": "String", + "phone": "String", + "address": "String", + "metadata": "String", + } +) + +NULLABLE_STRIPE_SUBSCRIPTION_COLUMNS = _nullable_columns( + { + "id": "String", + "customer": "String", + "plan": "String", + "created": "Int64", + "ended_at": "Int64", + "status": "String", + "metadata": "String", + } +) + +CUSTOMER_TEST_BUCKET = "test_storage_bucket-posthog.revenue_analytics.customer_metadata_resolution.stripe_customers" +SUBSCRIPTION_TEST_BUCKET = ( + "test_storage_bucket-posthog.revenue_analytics.customer_metadata_resolution.stripe_subscriptions" +) +INVOICE_TEST_BUCKET = "test_storage_bucket-posthog.revenue_analytics.customer_metadata_resolution.stripe_invoices" +CHARGE_TEST_BUCKET = "test_storage_bucket-posthog.revenue_analytics.customer_metadata_resolution.stripe_charges" + + +class TestStripeCustomerMetadataResolution(ClickhouseTestMixin, APIBaseTest): + QUERY_TIMESTAMP = "2025-04-21" + + def setUp(self): + super().setUp() + + self.customer_csv = tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) + self.customer_csv.write( + "id,created,name,email,phone,address,metadata\n" + 'cus_no_meta,1672531200,"Alice","alice@example.com","","{}",' + '"{}"\n' + 'cus_with_meta,1672531200,"Bob","bob@example.com","","{}",' + '"{""posthog_person_distinct_id"": ""bob_distinct""}"\n' + 'cus_no_sub,1672531200,"Charlie","charlie@example.com","","{}",' + '"{}"\n' + ) + self.customer_csv.close() + + self.subscription_csv = tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) + self.subscription_csv.write( + "id,customer,plan,created,ended_at,status,metadata\n" + 'sub_1,cus_no_meta,"{}",1704067200,0,active,' + '"{""posthog_person_distinct_id"": ""alice_distinct""}"\n' + ) + self.subscription_csv.close() + + self.invoice_csv = tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) + self.invoice_csv.write( + "id,tax,paid,lines,total,charge,issuer,number,object,status,created,currency,customer," + "discount,due_date,livemode,metadata,subtotal,attempted,discounts,rendering,amount_due," + "period_start,period_end,amount_paid,description,invoice_pdf,account_name,auto_advance," + "effective_at,subscription,attempt_count,automatic_tax,customer_name,billing_reason," + "customer_email,ending_balance,payment_intent,account_country,amount_shipping," + "amount_remaining,customer_address,customer_tax_ids,paid_out_of_band,payment_settings," + "starting_balance,collection_method,default_tax_rates,total_tax_amounts," + "hosted_invoice_url,status_transitions,customer_tax_exempt,total_excluding_tax," + "subscription_details,webhooks_delivered_at,subtotal_excluding_tax," + "total_discount_amounts,pre_payment_credit_notes_amount,post_payment_credit_notes_amount\n" + 'in_1,0,1,"{}",1549,ch_1,"{}",SH-0001,invoice,paid,1704067200,usd,cus_no_meta,' + ',,0,"{}",1549,1,"[]",,1549,1704067200,1706745600,1549,,,StreamHog,1,1704067200,' + 'sub_1,1,"{}",Alice,subscription_create,alice@example.com,0,pi_1,US,0,0,,,0,"{}",0,' + 'charge_automatically,"[]","[]",,"{}",none,1549,"{}",1704067200,1549,"[]",0,0\n' + ) + self.invoice_csv.close() + + self.charge_csv = tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) + self.charge_csv.write( + "id,paid,amount,object,source,status,created,invoice,outcome,captured,currency,customer," + "disputed,livemode,metadata,refunded,description,receipt_url,failure_code,fraud_details," + "radar_options,receipt_email,payment_intent,payment_method,amount_captured,amount_refunded," + "billing_details,failure_message,balance_transaction,statement_descriptor," + "payment_method_details,calculated_statement_descriptor\n" + 'ch_1,1,1549,charge,,succeeded,1704067200,in_1,"{}",1,usd,cus_no_meta,' + '0,0,"{}",0,Payment,,,,,,pi_1,pm_1,1549,0,"{}",,,STREAMHOG,"{}",STREAMHOG\n' + ) + self.charge_csv.close() + + self.customers_table, self.source, self.credential, _, self.customers_cleanup = ( + create_data_warehouse_table_from_csv( + Path(self.customer_csv.name), + "stripe_customer", + NULLABLE_STRIPE_CUSTOMER_COLUMNS, + CUSTOMER_TEST_BUCKET, + self.team, + ) + ) + + self.subscriptions_table, _, _, _, self.subscriptions_cleanup = create_data_warehouse_table_from_csv( + Path(self.subscription_csv.name), + "stripe_subscription", + NULLABLE_STRIPE_SUBSCRIPTION_COLUMNS, + SUBSCRIPTION_TEST_BUCKET, + self.team, + source=self.source, + credential=self.credential, + ) + + self.invoices_table, _, _, _, self.invoices_cleanup = create_data_warehouse_table_from_csv( + Path(self.invoice_csv.name), + "stripe_invoice", + STRIPE_INVOICE_COLUMNS, + INVOICE_TEST_BUCKET, + self.team, + source=self.source, + credential=self.credential, + ) + + self.charges_table, _, _, _, self.charges_cleanup = create_data_warehouse_table_from_csv( + Path(self.charge_csv.name), + "stripe_charge", + STRIPE_CHARGE_COLUMNS, + CHARGE_TEST_BUCKET, + self.team, + source=self.source, + credential=self.credential, + ) + + for name, table in [ + (STRIPE_CUSTOMER_RESOURCE_NAME, self.customers_table), + (STRIPE_SUBSCRIPTION_RESOURCE_NAME, self.subscriptions_table), + (STRIPE_INVOICE_RESOURCE_NAME, self.invoices_table), + (STRIPE_CHARGE_RESOURCE_NAME, self.charges_table), + ]: + ExternalDataSchema.objects.create( + team=self.team, + name=name, + source=self.source, + table=table, + should_sync=True, + last_synced_at="2024-01-01", + ) + + self.team.base_currency = CurrencyCode.USD.value + self.team.save() + + def tearDown(self): + self.customers_cleanup() + self.subscriptions_cleanup() + self.invoices_cleanup() + self.charges_cleanup() + for f in [self.customer_csv, self.subscription_csv, self.invoice_csv, self.charge_csv]: + Path(f.name).unlink(missing_ok=True) + super().tearDown() + + def _run_top_customers_query(self) -> RevenueAnalyticsTopCustomersQueryResponse: + with freeze_time(self.QUERY_TIMESTAMP): + query = RevenueAnalyticsTopCustomersQuery( + dateRange=DateRange(date_from="all"), + groupBy=RevenueAnalyticsTopCustomersGroupBy.ALL, + properties=[], + ) + runner = RevenueAnalyticsTopCustomersQueryRunner( + team=self.team, + query=query, + modifiers=HogQLQueryModifiers(formatCsvAllowDoubleQuotes=True), + ) + response = runner.calculate() + RevenueAnalyticsTopCustomersQueryResponse.model_validate(response) + return response + + def test_top_customers_query_works_with_nullable_metadata_columns(self): + response = self._run_top_customers_query() + + self.assertIsNotNone(response) diff --git a/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer_persons_join.py b/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer_persons_join.py deleted file mode 100644 index e7a68c15aa0d..000000000000 --- a/products/revenue_analytics/backend/views/sources/test/stripe/test_stripe_customer_persons_join.py +++ /dev/null @@ -1,44 +0,0 @@ -from freezegun import freeze_time -from posthog.test.base import _create_person - -from posthog.schema import CurrencyCode - -from posthog.hogql.database.schema.test.base import RevenueAnalyticsTestBase -from posthog.hogql.parser import parse_select -from posthog.hogql.query import execute_hogql_query - -from products.data_warehouse.backend.data_load.source_templates import _revenue_view_name, database_operations - - -class TestCustomerRevenueViewPersonsJoin(RevenueAnalyticsTestBase): - """Verify that the joins created by database_operations actually resolve - when revenue analytics queries through them.""" - - def setUp(self): - super().setUp() - self.create_sources() - self.team.base_currency = CurrencyCode.GBP.value - self.team.save() - self.view_name = _revenue_view_name(self.source.prefix or "") - - def test_persons_join_resolves_on_customer_view(self): - _create_person( - team_id=self.team.pk, - distinct_ids=["person_cus_1"], - properties={"marker": "found"}, - ) - - database_operations(self.team.pk, self.source.prefix or "") - - with freeze_time(self.QUERY_TIMESTAMP): - response = execute_hogql_query( - parse_select( - f"SELECT id, persons.properties.marker FROM {self.view_name}" - f" WHERE persons.properties.marker IS NOT NULL ORDER BY id" - ), - self.team, - modifiers=self.MODIFIERS, - ) - assert len(response.results) == 1 - assert response.results[0][0] == "cus_1" - assert response.results[0][1] == "found"