From b990eeb50bafa90f717adf70513f8fe708664ee6 Mon Sep 17 00:00:00 2001 From: Courtney Holcomb Date: Thu, 14 Nov 2024 13:26:07 -0800 Subject: [PATCH] Add test to demonstrate bug --- .../simple_manifest/metrics.yaml | 20 +- .../test_derived_metric_rendering.py | 37 + ...fset_metric_with_tiered_filters__plan0.sql | 665 ++++++++++++++++++ ...c_with_tiered_filters__plan0_optimized.sql | 107 +++ 4 files changed, 827 insertions(+), 2 deletions(-) create mode 100644 tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0.sql create mode 100644 tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0_optimized.sql diff --git a/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml b/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml index fe28fb047..39300f648 100644 --- a/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml +++ b/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml @@ -700,7 +700,7 @@ metric: alias: bookings_2_weeks_ago --- metric: - name: "bookings_offset_once" + name: bookings_offset_once description: bookings metric offset once. type: derived type_params: @@ -710,7 +710,7 @@ metric: offset_window: 5 days --- metric: - name: "bookings_offset_twice" + name: bookings_offset_twice description: bookings metric offset twice. type: derived type_params: @@ -719,6 +719,22 @@ metric: - name: bookings_offset_once offset_window: 2 days --- +metric: + name: bookings_offset_twice_with_tiered_filters + description: bookings metric offset twice with tiered filters + type: derived + type_params: + expr: bookings + metrics: + - name: bookings_offset_once + offset_window: 1 month + filter: + - "{{ TimeDimension('metric_time', 'month') }} >= '2019-01-01'" + - "{{ Dimension('booking__is_instant') }}" + filter: + - "{{ TimeDimension('metric_time', 'year') }} >= '2020-01-01'" + - "{{ Entity('listing') }} IS NOT NULL" +--- metric: name: bookings_at_start_of_month description: | diff --git a/tests_metricflow/query_rendering/test_derived_metric_rendering.py b/tests_metricflow/query_rendering/test_derived_metric_rendering.py index b0985915f..d756ff9a6 100644 --- a/tests_metricflow/query_rendering/test_derived_metric_rendering.py +++ b/tests_metricflow/query_rendering/test_derived_metric_rendering.py @@ -821,3 +821,40 @@ def test_derived_metric_that_defines_the_same_alias_in_different_components( dataflow_plan_builder=dataflow_plan_builder, query_spec=query_spec, ) + + +@pytest.mark.sql_engine_snapshot +def test_nested_offset_metric_with_tiered_filters( + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + dataflow_plan_builder: DataflowPlanBuilder, + query_parser: MetricFlowQueryParser, + sql_client: SqlClient, + dataflow_to_sql_converter: DataflowToSqlQueryPlanConverter, +) -> None: + """Tests that filters at different tiers are applied appropriately for derived metrics. + + This includes filters at the input metric, metric, and query level. At each tier there are filters on both + metric_time / agg time and another dimension, which might have different behaviors. + """ + # TODO: test with Trino, hard-coded filters might fail + query_spec = query_parser.parse_and_validate_query( + metric_names=("bookings_offset_twice_with_tiered_filters",), + group_by_names=("metric_time__day",), + where_constraints=[ + # `booking_ds` is the agg_time_dimension + PydanticWhereFilter(where_sql_template=("{{ TimeDimension('booking__ds', 'quarter') }} = '2021-01-01'")), + PydanticWhereFilter( + where_sql_template=("{{ TimeDimension('listing__created_at', 'day') }} = '2021-01-01'") + ), + ], + ).query_spec + + render_and_check( + request=request, + mf_test_configuration=mf_test_configuration, + dataflow_to_sql_converter=dataflow_to_sql_converter, + sql_client=sql_client, + dataflow_plan_builder=dataflow_plan_builder, + query_spec=query_spec, + ) diff --git a/tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0.sql b/tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0.sql new file mode 100644 index 000000000..a4efcd763 --- /dev/null +++ b/tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0.sql @@ -0,0 +1,665 @@ +test_name: test_nested_offset_metric_with_tiered_filters +test_filename: test_derived_metric_rendering.py +docstring: + Tests that filters at different tiers are applied appropriately for derived metrics. + + This includes filters at the input metric, metric, and query level. At each tier there are filters on both + metric_time / agg time and another dimension, which might have different behaviors. +sql_engine: DuckDB +--- +-- Compute Metrics via Expressions +SELECT + subq_17.metric_time__day + , bookings AS bookings_offset_twice_with_tiered_filters +FROM ( + -- Pass Only Elements: ['metric_time__day', 'bookings_offset_once'] + SELECT + subq_16.metric_time__day + , subq_16.bookings_offset_once + FROM ( + -- Constrain Output with WHERE + SELECT + subq_15.metric_time__day + , subq_15.metric_time__month + , subq_15.metric_time__year + , subq_15.booking__ds__quarter + , subq_15.listing__created_at__day + , subq_15.listing + , subq_15.booking__is_instant + , subq_15.bookings_offset_once + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_13.metric_time__day AS metric_time__day + , DATE_TRUNC('month', subq_13.metric_time__day) AS metric_time__month + , DATE_TRUNC('year', subq_13.metric_time__day) AS metric_time__year + , subq_12.booking__ds__quarter AS booking__ds__quarter + , subq_12.listing__created_at__day AS listing__created_at__day + , subq_12.listing AS listing + , subq_12.booking__is_instant AS booking__is_instant + , subq_12.bookings_offset_once AS bookings_offset_once + FROM ( + -- Time Spine + SELECT + subq_14.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_14 + ) subq_13 + INNER JOIN ( + -- Compute Metrics via Expressions + SELECT + subq_11.metric_time__day + , subq_11.metric_time__month + , subq_11.metric_time__year + , subq_11.booking__ds__quarter + , subq_11.listing__created_at__day + , subq_11.listing + , subq_11.booking__is_instant + , 2 * bookings AS bookings_offset_once + FROM ( + -- Compute Metrics via Expressions + SELECT + subq_10.metric_time__day + , subq_10.metric_time__month + , subq_10.metric_time__year + , subq_10.booking__ds__quarter + , subq_10.listing__created_at__day + , subq_10.listing + , subq_10.booking__is_instant + , subq_10.bookings + FROM ( + -- Aggregate Measures + SELECT + subq_9.metric_time__day + , subq_9.metric_time__month + , subq_9.metric_time__year + , subq_9.booking__ds__quarter + , subq_9.listing__created_at__day + , subq_9.listing + , subq_9.booking__is_instant + , SUM(subq_9.bookings) AS bookings + FROM ( + -- Pass Only Elements: [ + -- 'bookings', + -- 'booking__is_instant', + -- 'metric_time__day', + -- 'metric_time__year', + -- 'metric_time__month', + -- 'booking__ds__quarter', + -- 'listing__created_at__day', + -- 'listing', + -- ] + SELECT + subq_8.metric_time__day + , subq_8.metric_time__month + , subq_8.metric_time__year + , subq_8.booking__ds__quarter + , subq_8.listing__created_at__day + , subq_8.listing + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join Standard Outputs + SELECT + subq_7.created_at__day AS listing__created_at__day + , subq_4.metric_time__day AS metric_time__day + , subq_4.metric_time__week AS metric_time__week + , subq_4.metric_time__month AS metric_time__month + , subq_4.metric_time__quarter AS metric_time__quarter + , subq_4.metric_time__year AS metric_time__year + , subq_4.metric_time__extract_year AS metric_time__extract_year + , subq_4.metric_time__extract_quarter AS metric_time__extract_quarter + , subq_4.metric_time__extract_month AS metric_time__extract_month + , subq_4.metric_time__extract_day AS metric_time__extract_day + , subq_4.metric_time__extract_dow AS metric_time__extract_dow + , subq_4.metric_time__extract_doy AS metric_time__extract_doy + , subq_4.ds__day AS ds__day + , subq_4.ds__week AS ds__week + , subq_4.ds__month AS ds__month + , subq_4.ds__quarter AS ds__quarter + , subq_4.ds__year AS ds__year + , subq_4.ds__extract_year AS ds__extract_year + , subq_4.ds__extract_quarter AS ds__extract_quarter + , subq_4.ds__extract_month AS ds__extract_month + , subq_4.ds__extract_day AS ds__extract_day + , subq_4.ds__extract_dow AS ds__extract_dow + , subq_4.ds__extract_doy AS ds__extract_doy + , subq_4.ds_partitioned__day AS ds_partitioned__day + , subq_4.ds_partitioned__week AS ds_partitioned__week + , subq_4.ds_partitioned__month AS ds_partitioned__month + , subq_4.ds_partitioned__quarter AS ds_partitioned__quarter + , subq_4.ds_partitioned__year AS ds_partitioned__year + , subq_4.ds_partitioned__extract_year AS ds_partitioned__extract_year + , subq_4.ds_partitioned__extract_quarter AS ds_partitioned__extract_quarter + , subq_4.ds_partitioned__extract_month AS ds_partitioned__extract_month + , subq_4.ds_partitioned__extract_day AS ds_partitioned__extract_day + , subq_4.ds_partitioned__extract_dow AS ds_partitioned__extract_dow + , subq_4.ds_partitioned__extract_doy AS ds_partitioned__extract_doy + , subq_4.paid_at__day AS paid_at__day + , subq_4.paid_at__week AS paid_at__week + , subq_4.paid_at__month AS paid_at__month + , subq_4.paid_at__quarter AS paid_at__quarter + , subq_4.paid_at__year AS paid_at__year + , subq_4.paid_at__extract_year AS paid_at__extract_year + , subq_4.paid_at__extract_quarter AS paid_at__extract_quarter + , subq_4.paid_at__extract_month AS paid_at__extract_month + , subq_4.paid_at__extract_day AS paid_at__extract_day + , subq_4.paid_at__extract_dow AS paid_at__extract_dow + , subq_4.paid_at__extract_doy AS paid_at__extract_doy + , subq_4.booking__ds__day AS booking__ds__day + , subq_4.booking__ds__week AS booking__ds__week + , subq_4.booking__ds__month AS booking__ds__month + , subq_4.booking__ds__quarter AS booking__ds__quarter + , subq_4.booking__ds__year AS booking__ds__year + , subq_4.booking__ds__extract_year AS booking__ds__extract_year + , subq_4.booking__ds__extract_quarter AS booking__ds__extract_quarter + , subq_4.booking__ds__extract_month AS booking__ds__extract_month + , subq_4.booking__ds__extract_day AS booking__ds__extract_day + , subq_4.booking__ds__extract_dow AS booking__ds__extract_dow + , subq_4.booking__ds__extract_doy AS booking__ds__extract_doy + , subq_4.booking__ds_partitioned__day AS booking__ds_partitioned__day + , subq_4.booking__ds_partitioned__week AS booking__ds_partitioned__week + , subq_4.booking__ds_partitioned__month AS booking__ds_partitioned__month + , subq_4.booking__ds_partitioned__quarter AS booking__ds_partitioned__quarter + , subq_4.booking__ds_partitioned__year AS booking__ds_partitioned__year + , subq_4.booking__ds_partitioned__extract_year AS booking__ds_partitioned__extract_year + , subq_4.booking__ds_partitioned__extract_quarter AS booking__ds_partitioned__extract_quarter + , subq_4.booking__ds_partitioned__extract_month AS booking__ds_partitioned__extract_month + , subq_4.booking__ds_partitioned__extract_day AS booking__ds_partitioned__extract_day + , subq_4.booking__ds_partitioned__extract_dow AS booking__ds_partitioned__extract_dow + , subq_4.booking__ds_partitioned__extract_doy AS booking__ds_partitioned__extract_doy + , subq_4.booking__paid_at__day AS booking__paid_at__day + , subq_4.booking__paid_at__week AS booking__paid_at__week + , subq_4.booking__paid_at__month AS booking__paid_at__month + , subq_4.booking__paid_at__quarter AS booking__paid_at__quarter + , subq_4.booking__paid_at__year AS booking__paid_at__year + , subq_4.booking__paid_at__extract_year AS booking__paid_at__extract_year + , subq_4.booking__paid_at__extract_quarter AS booking__paid_at__extract_quarter + , subq_4.booking__paid_at__extract_month AS booking__paid_at__extract_month + , subq_4.booking__paid_at__extract_day AS booking__paid_at__extract_day + , subq_4.booking__paid_at__extract_dow AS booking__paid_at__extract_dow + , subq_4.booking__paid_at__extract_doy AS booking__paid_at__extract_doy + , subq_4.listing AS listing + , subq_4.guest AS guest + , subq_4.host AS host + , subq_4.booking__listing AS booking__listing + , subq_4.booking__guest AS booking__guest + , subq_4.booking__host AS booking__host + , subq_4.is_instant AS is_instant + , subq_4.booking__is_instant AS booking__is_instant + , subq_4.bookings AS bookings + , subq_4.instant_bookings AS instant_bookings + , subq_4.booking_value AS booking_value + , subq_4.max_booking_value AS max_booking_value + , subq_4.min_booking_value AS min_booking_value + , subq_4.bookers AS bookers + , subq_4.average_booking_value AS average_booking_value + , subq_4.referred_bookings AS referred_bookings + , subq_4.median_booking_value AS median_booking_value + , subq_4.booking_value_p99 AS booking_value_p99 + , subq_4.discrete_booking_value_p99 AS discrete_booking_value_p99 + , subq_4.approximate_continuous_booking_value_p99 AS approximate_continuous_booking_value_p99 + , subq_4.approximate_discrete_booking_value_p99 AS approximate_discrete_booking_value_p99 + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_2.metric_time__day AS metric_time__day + , DATE_TRUNC('week', subq_2.metric_time__day) AS metric_time__week + , DATE_TRUNC('month', subq_2.metric_time__day) AS metric_time__month + , DATE_TRUNC('quarter', subq_2.metric_time__day) AS metric_time__quarter + , DATE_TRUNC('year', subq_2.metric_time__day) AS metric_time__year + , EXTRACT(year FROM subq_2.metric_time__day) AS metric_time__extract_year + , EXTRACT(quarter FROM subq_2.metric_time__day) AS metric_time__extract_quarter + , EXTRACT(month FROM subq_2.metric_time__day) AS metric_time__extract_month + , EXTRACT(day FROM subq_2.metric_time__day) AS metric_time__extract_day + , EXTRACT(isodow FROM subq_2.metric_time__day) AS metric_time__extract_dow + , EXTRACT(doy FROM subq_2.metric_time__day) AS metric_time__extract_doy + , subq_1.ds__day AS ds__day + , subq_1.ds__week AS ds__week + , subq_1.ds__month AS ds__month + , subq_1.ds__quarter AS ds__quarter + , subq_1.ds__year AS ds__year + , subq_1.ds__extract_year AS ds__extract_year + , subq_1.ds__extract_quarter AS ds__extract_quarter + , subq_1.ds__extract_month AS ds__extract_month + , subq_1.ds__extract_day AS ds__extract_day + , subq_1.ds__extract_dow AS ds__extract_dow + , subq_1.ds__extract_doy AS ds__extract_doy + , subq_1.ds_partitioned__day AS ds_partitioned__day + , subq_1.ds_partitioned__week AS ds_partitioned__week + , subq_1.ds_partitioned__month AS ds_partitioned__month + , subq_1.ds_partitioned__quarter AS ds_partitioned__quarter + , subq_1.ds_partitioned__year AS ds_partitioned__year + , subq_1.ds_partitioned__extract_year AS ds_partitioned__extract_year + , subq_1.ds_partitioned__extract_quarter AS ds_partitioned__extract_quarter + , subq_1.ds_partitioned__extract_month AS ds_partitioned__extract_month + , subq_1.ds_partitioned__extract_day AS ds_partitioned__extract_day + , subq_1.ds_partitioned__extract_dow AS ds_partitioned__extract_dow + , subq_1.ds_partitioned__extract_doy AS ds_partitioned__extract_doy + , subq_1.paid_at__day AS paid_at__day + , subq_1.paid_at__week AS paid_at__week + , subq_1.paid_at__month AS paid_at__month + , subq_1.paid_at__quarter AS paid_at__quarter + , subq_1.paid_at__year AS paid_at__year + , subq_1.paid_at__extract_year AS paid_at__extract_year + , subq_1.paid_at__extract_quarter AS paid_at__extract_quarter + , subq_1.paid_at__extract_month AS paid_at__extract_month + , subq_1.paid_at__extract_day AS paid_at__extract_day + , subq_1.paid_at__extract_dow AS paid_at__extract_dow + , subq_1.paid_at__extract_doy AS paid_at__extract_doy + , subq_1.booking__ds__day AS booking__ds__day + , subq_1.booking__ds__week AS booking__ds__week + , subq_1.booking__ds__month AS booking__ds__month + , subq_1.booking__ds__quarter AS booking__ds__quarter + , subq_1.booking__ds__year AS booking__ds__year + , subq_1.booking__ds__extract_year AS booking__ds__extract_year + , subq_1.booking__ds__extract_quarter AS booking__ds__extract_quarter + , subq_1.booking__ds__extract_month AS booking__ds__extract_month + , subq_1.booking__ds__extract_day AS booking__ds__extract_day + , subq_1.booking__ds__extract_dow AS booking__ds__extract_dow + , subq_1.booking__ds__extract_doy AS booking__ds__extract_doy + , subq_1.booking__ds_partitioned__day AS booking__ds_partitioned__day + , subq_1.booking__ds_partitioned__week AS booking__ds_partitioned__week + , subq_1.booking__ds_partitioned__month AS booking__ds_partitioned__month + , subq_1.booking__ds_partitioned__quarter AS booking__ds_partitioned__quarter + , subq_1.booking__ds_partitioned__year AS booking__ds_partitioned__year + , subq_1.booking__ds_partitioned__extract_year AS booking__ds_partitioned__extract_year + , subq_1.booking__ds_partitioned__extract_quarter AS booking__ds_partitioned__extract_quarter + , subq_1.booking__ds_partitioned__extract_month AS booking__ds_partitioned__extract_month + , subq_1.booking__ds_partitioned__extract_day AS booking__ds_partitioned__extract_day + , subq_1.booking__ds_partitioned__extract_dow AS booking__ds_partitioned__extract_dow + , subq_1.booking__ds_partitioned__extract_doy AS booking__ds_partitioned__extract_doy + , subq_1.booking__paid_at__day AS booking__paid_at__day + , subq_1.booking__paid_at__week AS booking__paid_at__week + , subq_1.booking__paid_at__month AS booking__paid_at__month + , subq_1.booking__paid_at__quarter AS booking__paid_at__quarter + , subq_1.booking__paid_at__year AS booking__paid_at__year + , subq_1.booking__paid_at__extract_year AS booking__paid_at__extract_year + , subq_1.booking__paid_at__extract_quarter AS booking__paid_at__extract_quarter + , subq_1.booking__paid_at__extract_month AS booking__paid_at__extract_month + , subq_1.booking__paid_at__extract_day AS booking__paid_at__extract_day + , subq_1.booking__paid_at__extract_dow AS booking__paid_at__extract_dow + , subq_1.booking__paid_at__extract_doy AS booking__paid_at__extract_doy + , subq_1.listing AS listing + , subq_1.guest AS guest + , subq_1.host AS host + , subq_1.booking__listing AS booking__listing + , subq_1.booking__guest AS booking__guest + , subq_1.booking__host AS booking__host + , subq_1.is_instant AS is_instant + , subq_1.booking__is_instant AS booking__is_instant + , subq_1.bookings AS bookings + , subq_1.instant_bookings AS instant_bookings + , subq_1.booking_value AS booking_value + , subq_1.max_booking_value AS max_booking_value + , subq_1.min_booking_value AS min_booking_value + , subq_1.bookers AS bookers + , subq_1.average_booking_value AS average_booking_value + , subq_1.referred_bookings AS referred_bookings + , subq_1.median_booking_value AS median_booking_value + , subq_1.booking_value_p99 AS booking_value_p99 + , subq_1.discrete_booking_value_p99 AS discrete_booking_value_p99 + , subq_1.approximate_continuous_booking_value_p99 AS approximate_continuous_booking_value_p99 + , subq_1.approximate_discrete_booking_value_p99 AS approximate_discrete_booking_value_p99 + FROM ( + -- Time Spine + SELECT + subq_3.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_3 + ) subq_2 + INNER JOIN ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds) AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.paid_at) AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds) AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ON + subq_2.metric_time__day - INTERVAL 5 day = subq_1.metric_time__day + ) subq_4 + LEFT OUTER JOIN ( + -- Pass Only Elements: ['created_at__day', 'listing'] + SELECT + subq_6.created_at__day + , subq_6.listing + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_5.ds__day + , subq_5.ds__week + , subq_5.ds__month + , subq_5.ds__quarter + , subq_5.ds__year + , subq_5.ds__extract_year + , subq_5.ds__extract_quarter + , subq_5.ds__extract_month + , subq_5.ds__extract_day + , subq_5.ds__extract_dow + , subq_5.ds__extract_doy + , subq_5.created_at__day + , subq_5.created_at__week + , subq_5.created_at__month + , subq_5.created_at__quarter + , subq_5.created_at__year + , subq_5.created_at__extract_year + , subq_5.created_at__extract_quarter + , subq_5.created_at__extract_month + , subq_5.created_at__extract_day + , subq_5.created_at__extract_dow + , subq_5.created_at__extract_doy + , subq_5.listing__ds__day + , subq_5.listing__ds__week + , subq_5.listing__ds__month + , subq_5.listing__ds__quarter + , subq_5.listing__ds__year + , subq_5.listing__ds__extract_year + , subq_5.listing__ds__extract_quarter + , subq_5.listing__ds__extract_month + , subq_5.listing__ds__extract_day + , subq_5.listing__ds__extract_dow + , subq_5.listing__ds__extract_doy + , subq_5.listing__created_at__day + , subq_5.listing__created_at__week + , subq_5.listing__created_at__month + , subq_5.listing__created_at__quarter + , subq_5.listing__created_at__year + , subq_5.listing__created_at__extract_year + , subq_5.listing__created_at__extract_quarter + , subq_5.listing__created_at__extract_month + , subq_5.listing__created_at__extract_day + , subq_5.listing__created_at__extract_dow + , subq_5.listing__created_at__extract_doy + , subq_5.ds__day AS metric_time__day + , subq_5.ds__week AS metric_time__week + , subq_5.ds__month AS metric_time__month + , subq_5.ds__quarter AS metric_time__quarter + , subq_5.ds__year AS metric_time__year + , subq_5.ds__extract_year AS metric_time__extract_year + , subq_5.ds__extract_quarter AS metric_time__extract_quarter + , subq_5.ds__extract_month AS metric_time__extract_month + , subq_5.ds__extract_day AS metric_time__extract_day + , subq_5.ds__extract_dow AS metric_time__extract_dow + , subq_5.ds__extract_doy AS metric_time__extract_doy + , subq_5.listing + , subq_5.user + , subq_5.listing__user + , subq_5.country_latest + , subq_5.is_lux_latest + , subq_5.capacity_latest + , subq_5.listing__country_latest + , subq_5.listing__is_lux_latest + , subq_5.listing__capacity_latest + , subq_5.listings + , subq_5.largest_listing + , subq_5.smallest_listing + FROM ( + -- Read Elements From Semantic Model 'listings_latest' + SELECT + 1 AS listings + , listings_latest_src_28000.capacity AS largest_listing + , listings_latest_src_28000.capacity AS smallest_listing + , DATE_TRUNC('day', listings_latest_src_28000.created_at) AS ds__day + , DATE_TRUNC('week', listings_latest_src_28000.created_at) AS ds__week + , DATE_TRUNC('month', listings_latest_src_28000.created_at) AS ds__month + , DATE_TRUNC('quarter', listings_latest_src_28000.created_at) AS ds__quarter + , DATE_TRUNC('year', listings_latest_src_28000.created_at) AS ds__year + , EXTRACT(year FROM listings_latest_src_28000.created_at) AS ds__extract_year + , EXTRACT(quarter FROM listings_latest_src_28000.created_at) AS ds__extract_quarter + , EXTRACT(month FROM listings_latest_src_28000.created_at) AS ds__extract_month + , EXTRACT(day FROM listings_latest_src_28000.created_at) AS ds__extract_day + , EXTRACT(isodow FROM listings_latest_src_28000.created_at) AS ds__extract_dow + , EXTRACT(doy FROM listings_latest_src_28000.created_at) AS ds__extract_doy + , DATE_TRUNC('day', listings_latest_src_28000.created_at) AS created_at__day + , DATE_TRUNC('week', listings_latest_src_28000.created_at) AS created_at__week + , DATE_TRUNC('month', listings_latest_src_28000.created_at) AS created_at__month + , DATE_TRUNC('quarter', listings_latest_src_28000.created_at) AS created_at__quarter + , DATE_TRUNC('year', listings_latest_src_28000.created_at) AS created_at__year + , EXTRACT(year FROM listings_latest_src_28000.created_at) AS created_at__extract_year + , EXTRACT(quarter FROM listings_latest_src_28000.created_at) AS created_at__extract_quarter + , EXTRACT(month FROM listings_latest_src_28000.created_at) AS created_at__extract_month + , EXTRACT(day FROM listings_latest_src_28000.created_at) AS created_at__extract_day + , EXTRACT(isodow FROM listings_latest_src_28000.created_at) AS created_at__extract_dow + , EXTRACT(doy FROM listings_latest_src_28000.created_at) AS created_at__extract_doy + , listings_latest_src_28000.country AS country_latest + , listings_latest_src_28000.is_lux AS is_lux_latest + , listings_latest_src_28000.capacity AS capacity_latest + , DATE_TRUNC('day', listings_latest_src_28000.created_at) AS listing__ds__day + , DATE_TRUNC('week', listings_latest_src_28000.created_at) AS listing__ds__week + , DATE_TRUNC('month', listings_latest_src_28000.created_at) AS listing__ds__month + , DATE_TRUNC('quarter', listings_latest_src_28000.created_at) AS listing__ds__quarter + , DATE_TRUNC('year', listings_latest_src_28000.created_at) AS listing__ds__year + , EXTRACT(year FROM listings_latest_src_28000.created_at) AS listing__ds__extract_year + , EXTRACT(quarter FROM listings_latest_src_28000.created_at) AS listing__ds__extract_quarter + , EXTRACT(month FROM listings_latest_src_28000.created_at) AS listing__ds__extract_month + , EXTRACT(day FROM listings_latest_src_28000.created_at) AS listing__ds__extract_day + , EXTRACT(isodow FROM listings_latest_src_28000.created_at) AS listing__ds__extract_dow + , EXTRACT(doy FROM listings_latest_src_28000.created_at) AS listing__ds__extract_doy + , DATE_TRUNC('day', listings_latest_src_28000.created_at) AS listing__created_at__day + , DATE_TRUNC('week', listings_latest_src_28000.created_at) AS listing__created_at__week + , DATE_TRUNC('month', listings_latest_src_28000.created_at) AS listing__created_at__month + , DATE_TRUNC('quarter', listings_latest_src_28000.created_at) AS listing__created_at__quarter + , DATE_TRUNC('year', listings_latest_src_28000.created_at) AS listing__created_at__year + , EXTRACT(year FROM listings_latest_src_28000.created_at) AS listing__created_at__extract_year + , EXTRACT(quarter FROM listings_latest_src_28000.created_at) AS listing__created_at__extract_quarter + , EXTRACT(month FROM listings_latest_src_28000.created_at) AS listing__created_at__extract_month + , EXTRACT(day FROM listings_latest_src_28000.created_at) AS listing__created_at__extract_day + , EXTRACT(isodow FROM listings_latest_src_28000.created_at) AS listing__created_at__extract_dow + , EXTRACT(doy FROM listings_latest_src_28000.created_at) AS listing__created_at__extract_doy + , listings_latest_src_28000.country AS listing__country_latest + , listings_latest_src_28000.is_lux AS listing__is_lux_latest + , listings_latest_src_28000.capacity AS listing__capacity_latest + , listings_latest_src_28000.listing_id AS listing + , listings_latest_src_28000.user_id AS user + , listings_latest_src_28000.user_id AS listing__user + FROM ***************************.dim_listings_latest listings_latest_src_28000 + ) subq_5 + ) subq_6 + ) subq_7 + ON + subq_4.listing = subq_7.listing + ) subq_8 + ) subq_9 + GROUP BY + subq_9.metric_time__day + , subq_9.metric_time__month + , subq_9.metric_time__year + , subq_9.booking__ds__quarter + , subq_9.listing__created_at__day + , subq_9.listing + , subq_9.booking__is_instant + ) subq_10 + ) subq_11 + ) subq_12 + ON + subq_13.metric_time__day - INTERVAL 1 month = subq_12.metric_time__day + ) subq_15 + WHERE (((((metric_time__year >= '2020-01-01') AND (listing IS NOT NULL)) AND (metric_time__month >= '2019-01-01')) AND (booking__is_instant)) AND (booking__ds__quarter = '2021-01-01')) AND (listing__created_at__day = '2021-01-01') + ) subq_16 +) subq_17 diff --git a/tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0_optimized.sql b/tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0_optimized.sql new file mode 100644 index 000000000..9ed00626c --- /dev/null +++ b/tests_metricflow/snapshots/test_derived_metric_rendering.py/SqlQueryPlan/DuckDB/test_nested_offset_metric_with_tiered_filters__plan0_optimized.sql @@ -0,0 +1,107 @@ +test_name: test_nested_offset_metric_with_tiered_filters +test_filename: test_derived_metric_rendering.py +docstring: + Tests that filters at different tiers are applied appropriately for derived metrics. + + This includes filters at the input metric, metric, and query level. At each tier there are filters on both + metric_time / agg time and another dimension, which might have different behaviors. +sql_engine: DuckDB +--- +-- Compute Metrics via Expressions +SELECT + metric_time__day + , bookings AS bookings_offset_twice_with_tiered_filters +FROM ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['metric_time__day', 'bookings_offset_once'] + SELECT + metric_time__day + , bookings_offset_once + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_32.ds AS metric_time__day + , DATE_TRUNC('month', subq_32.ds) AS metric_time__month + , DATE_TRUNC('year', subq_32.ds) AS metric_time__year + , subq_30.booking__ds__quarter AS booking__ds__quarter + , subq_30.listing__created_at__day AS listing__created_at__day + , subq_30.listing AS listing + , subq_30.booking__is_instant AS booking__is_instant + , subq_30.bookings_offset_once AS bookings_offset_once + FROM ***************************.mf_time_spine subq_32 + INNER JOIN ( + -- Compute Metrics via Expressions + SELECT + metric_time__day + , booking__ds__quarter + , listing__created_at__day + , listing + , booking__is_instant + , 2 * bookings AS bookings_offset_once + FROM ( + -- Join Standard Outputs + -- Pass Only Elements: [ + -- 'bookings', + -- 'booking__is_instant', + -- 'metric_time__day', + -- 'metric_time__year', + -- 'metric_time__month', + -- 'booking__ds__quarter', + -- 'listing__created_at__day', + -- 'listing', + -- ] + -- Aggregate Measures + -- Compute Metrics via Expressions + SELECT + subq_22.metric_time__day AS metric_time__day + , subq_22.metric_time__month AS metric_time__month + , subq_22.metric_time__year AS metric_time__year + , subq_22.booking__ds__quarter AS booking__ds__quarter + , DATE_TRUNC('day', listings_latest_src_28000.created_at) AS listing__created_at__day + , subq_22.listing AS listing + , subq_22.booking__is_instant AS booking__is_instant + , SUM(subq_22.bookings) AS bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_21.ds AS metric_time__day + , DATE_TRUNC('month', subq_21.ds) AS metric_time__month + , DATE_TRUNC('year', subq_21.ds) AS metric_time__year + , subq_19.booking__ds__quarter AS booking__ds__quarter + , subq_19.listing AS listing + , subq_19.booking__is_instant AS booking__is_instant + , subq_19.bookings AS bookings + FROM ***************************.mf_time_spine subq_21 + INNER JOIN ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + SELECT + DATE_TRUNC('quarter', ds) AS booking__ds__quarter + , DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_19 + ON + subq_21.ds - INTERVAL 5 day = subq_19.metric_time__day + ) subq_22 + LEFT OUTER JOIN + ***************************.dim_listings_latest listings_latest_src_28000 + ON + subq_22.listing = listings_latest_src_28000.listing_id + GROUP BY + subq_22.metric_time__day + , subq_22.metric_time__month + , subq_22.metric_time__year + , subq_22.booking__ds__quarter + , DATE_TRUNC('day', listings_latest_src_28000.created_at) + , subq_22.listing + , subq_22.booking__is_instant + ) subq_29 + ) subq_30 + ON + subq_32.ds - INTERVAL 1 month = subq_30.metric_time__day + ) subq_33 + WHERE (((((metric_time__year >= '2020-01-01') AND (listing IS NOT NULL)) AND (metric_time__month >= '2019-01-01')) AND (booking__is_instant)) AND (booking__ds__quarter = '2021-01-01')) AND (listing__created_at__day = '2021-01-01') +) subq_35