diff --git a/metricflow/dataflow/builder/dataflow_plan_builder.py b/metricflow/dataflow/builder/dataflow_plan_builder.py
index b4ed743b9f..cac9cee58f 100644
--- a/metricflow/dataflow/builder/dataflow_plan_builder.py
+++ b/metricflow/dataflow/builder/dataflow_plan_builder.py
@@ -182,6 +182,7 @@ def _build_metrics_output_node(
for metric_spec in metric_specs:
logger.info(f"Generating compute metrics node for {metric_spec}")
+ join_to_time_spine_node: Optional[JoinToTimeSpineNode] = None
metric_reference = metric_spec.as_reference
metric = self._metric_lookup.get_metric(metric_reference)
@@ -203,6 +204,23 @@ def _build_metrics_output_node(
),
metric_specs=[metric_spec],
)
+
+ # For nested ratio / derived metrics with time offset, apply offset after metric computation.
+ if metric_spec.offset_window or metric_spec.offset_to_grain:
+ metric_time_dimension_specs = [
+ time_dimension_spec
+ for time_dimension_spec in queried_linkable_specs.time_dimension_specs
+ if time_dimension_spec.element_name == self._metric_time_dimension_reference.element_name
+ ]
+ assert metric_time_dimension_specs, "Joining to time spine requires querying with metric time."
+ join_to_time_spine_node = JoinToTimeSpineNode(
+ parent_node=compute_metrics_node,
+ requested_metric_time_dimension_specs=metric_time_dimension_specs,
+ time_range_constraint=time_range_constraint,
+ offset_window=metric_spec.offset_window,
+ offset_to_grain=metric_spec.offset_to_grain,
+ join_type=SqlJoinType.INNER,
+ )
elif metric.type is MetricType.SIMPLE or MetricType.CUMULATIVE:
metric_input_measure_specs = self._metric_lookup.measures_for_metric(
metric_reference=metric_reference,
@@ -243,7 +261,7 @@ def _build_metrics_output_node(
assert compute_metrics_node is not None
- output_nodes.append(compute_metrics_node)
+ output_nodes.append(join_to_time_spine_node or compute_metrics_node)
assert len(output_nodes) > 0, "ComputeMetricsNode was not properly constructed"
diff --git a/metricflow/dataflow/dataflow_plan.py b/metricflow/dataflow/dataflow_plan.py
index 94404d662a..cc9205be48 100644
--- a/metricflow/dataflow/dataflow_plan.py
+++ b/metricflow/dataflow/dataflow_plan.py
@@ -675,27 +675,27 @@ def id_prefix(cls) -> str: # noqa: D
return DATAFLOW_NODE_JOIN_TO_TIME_SPINE_ID_PREFIX
@property
- def requested_metric_time_dimension_specs(self) -> List[TimeDimensionSpec]: # noqa: D
+ def requested_metric_time_dimension_specs(self) -> List[TimeDimensionSpec]:
"""Time dimension specs to use when creating time spine table."""
return self._requested_metric_time_dimension_specs
@property
- def time_range_constraint(self) -> Optional[TimeRangeConstraint]: # noqa: D
+ def time_range_constraint(self) -> Optional[TimeRangeConstraint]:
"""Time range constraint to apply when querying time spine table."""
return self._time_range_constraint
@property
- def offset_window(self) -> Optional[MetricTimeWindow]: # noqa: D
+ def offset_window(self) -> Optional[MetricTimeWindow]:
"""Time range constraint to apply when querying time spine table."""
return self._offset_window
@property
- def offset_to_grain(self) -> Optional[TimeGranularity]: # noqa: D
+ def offset_to_grain(self) -> Optional[TimeGranularity]:
"""Time range constraint to apply when querying time spine table."""
return self._offset_to_grain
@property
- def join_type(self) -> SqlJoinType: # noqa: D
+ def join_type(self) -> SqlJoinType:
"""Join type to use when joining to time spine."""
return self._join_type
diff --git a/metricflow/test/dataflow/builder/test_dataflow_plan_builder.py b/metricflow/test/dataflow/builder/test_dataflow_plan_builder.py
index fdbe59fcbe..2235b2b5a8 100644
--- a/metricflow/test/dataflow/builder/test_dataflow_plan_builder.py
+++ b/metricflow/test/dataflow/builder/test_dataflow_plan_builder.py
@@ -972,3 +972,29 @@ def test_dont_join_to_time_spine_if_no_time_dimension_requested( # noqa: D
mf_test_session_state=mf_test_session_state,
dag_graph=dataflow_plan,
)
+
+
+def test_nested_derived_metric_with_outer_offset( # noqa: D
+ request: FixtureRequest,
+ mf_test_session_state: MetricFlowTestSessionState,
+ dataflow_plan_builder: DataflowPlanBuilder,
+) -> None:
+ dataflow_plan = dataflow_plan_builder.build_plan(
+ MetricFlowQuerySpec(
+ metric_specs=(MetricSpec(element_name="bookings_offset_twice"),),
+ time_dimension_specs=(DataSet.metric_time_dimension_spec(TimeGranularity.DAY),),
+ )
+ )
+
+ assert_plan_snapshot_text_equal(
+ request=request,
+ mf_test_session_state=mf_test_session_state,
+ plan=dataflow_plan,
+ plan_snapshot_text=dataflow_plan_as_text(dataflow_plan),
+ )
+
+ display_graph_if_requested(
+ request=request,
+ mf_test_session_state=mf_test_session_state,
+ dag_graph=dataflow_plan,
+ )
diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/metrics.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/metrics.yaml
index b6ba2318dc..16802cd2df 100644
--- a/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/metrics.yaml
+++ b/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/metrics.yaml
@@ -578,3 +578,35 @@ metric:
- name: bookings
offset_window: 14 days
alias: bookings_2_weeks_ago
+---
+metric:
+ name: "bookings_offset_once"
+ description: bookings metric offset once.
+ type: derived
+ type_params:
+ expr: 2 * bookings
+ metrics:
+ - name: bookings
+ offset_window: 5 days
+---
+metric:
+ name: "bookings_offset_twice"
+ description: bookings metric offset twice.
+ type: derived
+ type_params:
+ expr: 2 * bookings_offset_once
+ metrics:
+ - name: bookings_offset_once
+ offset_window: 5 days
+---
+metric:
+ name: booking_fees_since_start_of_month
+ description: nested derived metric with offset and multiple input metrics
+ type: derived
+ type_params:
+ expr: booking_fees - booking_fees_start_of_month
+ metrics:
+ - name: booking_fees
+ offset_to_grain: month
+ alias: booking_fees_start_of_month
+ - name: booking_fees
diff --git a/metricflow/test/integration/test_cases/itest_metrics.yaml b/metricflow/test/integration/test_cases/itest_metrics.yaml
index c0893e5c73..de7a087f31 100644
--- a/metricflow/test/integration/test_cases/itest_metrics.yaml
+++ b/metricflow/test/integration/test_cases/itest_metrics.yaml
@@ -1468,3 +1468,93 @@ integration_test:
GROUP BY
COALESCE(subq_9.metric_time__day, subq_19.metric_time__day)
, COALESCE(subq_9.listing__is_lux_latest, subq_19.listing__is_lux_latest)
+---
+integration_test:
+ name: nested_derived_metric_outer_offset
+ description: Tests a nested derived metric where the outer metric has an input metric with offset_window.
+ model: SIMPLE_MODEL
+ metrics: ["bookings_offset_twice"]
+ group_by_objs: [{"name": "metric_time"}]
+ check_query: |
+ SELECT
+ subq_9.ds AS metric_time__day
+ , 2 * bookings_offset_once AS bookings_offset_twice
+ FROM {{ source_schema }}.mf_time_spine subq_9
+ INNER JOIN (
+ SELECT
+ metric_time__day
+ , 2 * bookings AS bookings_offset_once
+ FROM (
+ SELECT
+ subq_3.ds AS metric_time__day
+ , SUM(subq_1.bookings) AS bookings
+ FROM {{ source_schema }}.mf_time_spine subq_3
+ INNER JOIN (
+ SELECT
+ {{ render_date_trunc("ds", TimeGranularity.DAY) }} AS metric_time__day
+ , 1 AS bookings
+ FROM {{ source_schema }}.fct_bookings bookings_source_src_1
+ ) subq_1
+ ON
+ {{ render_date_sub("subq_3", "ds", 5, TimeGranularity.DAY) }} = subq_1.metric_time__day
+ GROUP BY
+ subq_3.ds
+ ) subq_7
+ ) subq_8
+ ON
+ {{ render_date_sub("subq_9", "ds", 5, TimeGranularity.DAY) }} = subq_8.metric_time__day
+---
+integration_test:
+ name: nested_derived_metric_outer_offset_multiple_input_metrics
+ description: Tests a nested derived metric where the outer metric has one input metric with offset_to_grain and another with no offset.
+ model: SIMPLE_MODEL
+ metrics: ["booking_fees_since_start_of_month"]
+ group_by_objs: [{"name": "metric_time"}]
+ check_query: |
+ SELECT
+ metric_time__day
+ , booking_fees - booking_fees_start_of_month AS booking_fees_since_start_of_month
+ FROM (
+ SELECT
+ COALESCE(subq_8.metric_time__day, subq_14.metric_time__day) AS metric_time__day
+ , MAX(subq_8.booking_fees_start_of_month) AS booking_fees_start_of_month
+ , MAX(subq_14.booking_fees) AS booking_fees
+ FROM (
+ SELECT
+ subq_7.ds AS metric_time__day
+ , subq_5.booking_fees_start_of_month AS booking_fees_start_of_month
+ FROM {{ source_schema }}.mf_time_spine subq_7
+ INNER JOIN (
+ SELECT
+ metric_time__day
+ , booking_value * 0.05 AS booking_fees_start_of_month
+ FROM (
+ SELECT
+ {{ render_date_trunc("ds", TimeGranularity.DAY) }} AS metric_time__day
+ , SUM(booking_value) AS booking_value
+ FROM {{ source_schema }}.fct_bookings bookings_source_src_1
+ GROUP BY
+ {{ render_date_trunc("ds", TimeGranularity.DAY) }}
+ ) subq_4
+ ) subq_5
+ ON
+ {{ render_date_trunc("subq_7.ds", TimeGranularity.MONTH) }} = subq_5.metric_time__day
+ ) subq_8
+ FULL OUTER JOIN (
+ SELECT
+ metric_time__day
+ , booking_value * 0.05 AS booking_fees
+ FROM (
+ SELECT
+ {{ render_date_trunc("ds", TimeGranularity.DAY) }} AS metric_time__day
+ , SUM(booking_value) AS booking_value
+ FROM {{ source_schema }}.fct_bookings bookings_source_src_1
+ GROUP BY
+ {{ render_date_trunc("ds", TimeGranularity.DAY) }}
+ ) subq_13
+ ) subq_14
+ ON
+ subq_8.metric_time__day = subq_14.metric_time__day
+ GROUP BY
+ COALESCE(subq_8.metric_time__day, subq_14.metric_time__day)
+ ) subq_15
diff --git a/metricflow/test/plan_conversion/test_dataflow_to_sql_plan.py b/metricflow/test/plan_conversion/test_dataflow_to_sql_plan.py
index 25c3521924..790d2434a6 100644
--- a/metricflow/test/plan_conversion/test_dataflow_to_sql_plan.py
+++ b/metricflow/test/plan_conversion/test_dataflow_to_sql_plan.py
@@ -1,5 +1,6 @@
from __future__ import annotations
+import logging
from typing import List
import pytest
@@ -1035,3 +1036,56 @@ def test_dimensions_requiring_join(
sql_client=sql_client,
node=dataflow_plan.sink_output_nodes[0].parent_node,
)
+
+
+logger = logging.getLogger(__name__)
+
+
+@pytest.mark.sql_engine_snapshot
+def test_nested_offsets( # noqa: D
+ request: FixtureRequest,
+ mf_test_session_state: MetricFlowTestSessionState,
+ dataflow_plan_builder: DataflowPlanBuilder,
+ dataflow_to_sql_converter: DataflowToSqlQueryPlanConverter,
+ sql_client: SqlClient,
+ create_source_tables: bool,
+) -> None:
+ dataflow_plan = dataflow_plan_builder.build_plan(
+ query_spec=MetricFlowQuerySpec(
+ metric_specs=(MetricSpec(element_name="bookings_offset_twice"),),
+ time_dimension_specs=(MTD_SPEC_DAY,),
+ )
+ )
+
+ convert_and_check(
+ request=request,
+ mf_test_session_state=mf_test_session_state,
+ dataflow_to_sql_converter=dataflow_to_sql_converter,
+ sql_client=sql_client,
+ node=dataflow_plan.sink_output_nodes[0].parent_node,
+ )
+
+
+@pytest.mark.sql_engine_snapshot
+def test_nested_derived_metric_with_offset_multiple_input_metrics( # noqa: D
+ request: FixtureRequest,
+ mf_test_session_state: MetricFlowTestSessionState,
+ dataflow_plan_builder: DataflowPlanBuilder,
+ dataflow_to_sql_converter: DataflowToSqlQueryPlanConverter,
+ sql_client: SqlClient,
+ create_source_tables: bool,
+) -> None:
+ dataflow_plan = dataflow_plan_builder.build_plan(
+ query_spec=MetricFlowQuerySpec(
+ metric_specs=(MetricSpec(element_name="booking_fees_since_start_of_month"),),
+ time_dimension_specs=(MTD_SPEC_DAY,),
+ )
+ )
+
+ convert_and_check(
+ request=request,
+ mf_test_session_state=mf_test_session_state,
+ dataflow_to_sql_converter=dataflow_to_sql_converter,
+ sql_client=sql_client,
+ node=dataflow_plan.sink_output_nodes[0].parent_node,
+ )
diff --git a/metricflow/test/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml b/metricflow/test/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml
new file mode 100644
index 0000000000..fa8a153b72
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0.sql b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0.sql
new file mode 100644
index 0000000000..05cd13acc1
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0.sql
@@ -0,0 +1,473 @@
+-- Compute Metrics via Expressions
+SELECT
+ subq_15.metric_time__day
+ , booking_fees - booking_fees_start_of_month AS booking_fees_since_start_of_month
+FROM (
+ -- Combine Metrics
+ SELECT
+ COALESCE(subq_8.metric_time__day, subq_14.metric_time__day) AS metric_time__day
+ , MAX(subq_8.booking_fees_start_of_month) AS booking_fees_start_of_month
+ , MAX(subq_14.booking_fees) AS booking_fees
+ FROM (
+ -- Join to Time Spine Dataset
+ SELECT
+ subq_6.metric_time__day AS metric_time__day
+ , subq_5.booking_fees_start_of_month AS booking_fees_start_of_month
+ FROM (
+ -- Date Spine
+ SELECT
+ subq_7.ds AS metric_time__day
+ FROM ***************************.mf_time_spine subq_7
+ ) subq_6
+ INNER JOIN (
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_4.metric_time__day
+ , booking_value * 0.05 AS booking_fees_start_of_month
+ FROM (
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_3.metric_time__day
+ , subq_3.booking_value
+ FROM (
+ -- Aggregate Measures
+ SELECT
+ subq_2.metric_time__day
+ , SUM(subq_2.booking_value) AS booking_value
+ FROM (
+ -- Pass Only Elements:
+ -- ['booking_value', 'metric_time__day']
+ SELECT
+ subq_1.metric_time__day
+ , subq_1.booking_value
+ FROM (
+ -- 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_10001.booking_value
+ , bookings_source_src_10001.booking_value AS max_booking_value
+ , bookings_source_src_10001.booking_value AS min_booking_value
+ , bookings_source_src_10001.guest_id AS bookers
+ , bookings_source_src_10001.booking_value AS average_booking_value
+ , bookings_source_src_10001.booking_value AS booking_payments
+ , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings
+ , bookings_source_src_10001.booking_value AS median_booking_value
+ , bookings_source_src_10001.booking_value AS booking_value_p99
+ , bookings_source_src_10001.booking_value AS discrete_booking_value_p99
+ , bookings_source_src_10001.booking_value AS approximate_continuous_booking_value_p99
+ , bookings_source_src_10001.booking_value AS approximate_discrete_booking_value_p99
+ , bookings_source_src_10001.is_instant
+ , DATE_TRUNC('day', bookings_source_src_10001.ds) AS ds__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds) AS ds__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds) AS ds__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds) AS ds__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds) AS ds__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds) AS ds__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds) AS ds__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds) AS ds__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds) AS ds__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds) AS ds__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds) AS ds__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.paid_at) AS paid_at__day
+ , DATE_TRUNC('week', bookings_source_src_10001.paid_at) AS paid_at__week
+ , DATE_TRUNC('month', bookings_source_src_10001.paid_at) AS paid_at__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.paid_at) AS paid_at__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.paid_at) AS paid_at__year
+ , EXTRACT(year FROM bookings_source_src_10001.paid_at) AS paid_at__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.paid_at) AS paid_at__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.paid_at) AS paid_at__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.paid_at) AS paid_at__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.paid_at) AS paid_at__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.paid_at) AS paid_at__extract_doy
+ , bookings_source_src_10001.is_instant AS booking__is_instant
+ , DATE_TRUNC('day', bookings_source_src_10001.ds) AS booking__ds__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds) AS booking__ds__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds) AS booking__ds__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds) AS booking__ds__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds) AS booking__ds__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds) AS booking__ds__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds) AS booking__ds__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds) AS booking__ds__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds) AS booking__ds__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds) AS booking__ds__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds) AS booking__ds__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.paid_at) AS booking__paid_at__day
+ , DATE_TRUNC('week', bookings_source_src_10001.paid_at) AS booking__paid_at__week
+ , DATE_TRUNC('month', bookings_source_src_10001.paid_at) AS booking__paid_at__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.paid_at) AS booking__paid_at__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.paid_at) AS booking__paid_at__year
+ , EXTRACT(year FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_doy
+ , bookings_source_src_10001.listing_id AS listing
+ , bookings_source_src_10001.guest_id AS guest
+ , bookings_source_src_10001.host_id AS host
+ , bookings_source_src_10001.listing_id AS booking__listing
+ , bookings_source_src_10001.guest_id AS booking__guest
+ , bookings_source_src_10001.host_id AS booking__host
+ FROM ***************************.fct_bookings bookings_source_src_10001
+ ) subq_0
+ ) subq_1
+ ) subq_2
+ GROUP BY
+ subq_2.metric_time__day
+ ) subq_3
+ ) subq_4
+ ) subq_5
+ ON
+ DATE_TRUNC('month', subq_6.metric_time__day) = subq_5.metric_time__day
+ ) subq_8
+ FULL OUTER JOIN (
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_13.metric_time__day
+ , booking_value * 0.05 AS booking_fees
+ FROM (
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_12.metric_time__day
+ , subq_12.booking_value
+ FROM (
+ -- Aggregate Measures
+ SELECT
+ subq_11.metric_time__day
+ , SUM(subq_11.booking_value) AS booking_value
+ FROM (
+ -- Pass Only Elements:
+ -- ['booking_value', 'metric_time__day']
+ SELECT
+ subq_10.metric_time__day
+ , subq_10.booking_value
+ FROM (
+ -- Metric Time Dimension 'ds'
+ SELECT
+ subq_9.ds__day
+ , subq_9.ds__week
+ , subq_9.ds__month
+ , subq_9.ds__quarter
+ , subq_9.ds__year
+ , subq_9.ds__extract_year
+ , subq_9.ds__extract_quarter
+ , subq_9.ds__extract_month
+ , subq_9.ds__extract_day
+ , subq_9.ds__extract_dow
+ , subq_9.ds__extract_doy
+ , subq_9.ds_partitioned__day
+ , subq_9.ds_partitioned__week
+ , subq_9.ds_partitioned__month
+ , subq_9.ds_partitioned__quarter
+ , subq_9.ds_partitioned__year
+ , subq_9.ds_partitioned__extract_year
+ , subq_9.ds_partitioned__extract_quarter
+ , subq_9.ds_partitioned__extract_month
+ , subq_9.ds_partitioned__extract_day
+ , subq_9.ds_partitioned__extract_dow
+ , subq_9.ds_partitioned__extract_doy
+ , subq_9.paid_at__day
+ , subq_9.paid_at__week
+ , subq_9.paid_at__month
+ , subq_9.paid_at__quarter
+ , subq_9.paid_at__year
+ , subq_9.paid_at__extract_year
+ , subq_9.paid_at__extract_quarter
+ , subq_9.paid_at__extract_month
+ , subq_9.paid_at__extract_day
+ , subq_9.paid_at__extract_dow
+ , subq_9.paid_at__extract_doy
+ , subq_9.booking__ds__day
+ , subq_9.booking__ds__week
+ , subq_9.booking__ds__month
+ , subq_9.booking__ds__quarter
+ , subq_9.booking__ds__year
+ , subq_9.booking__ds__extract_year
+ , subq_9.booking__ds__extract_quarter
+ , subq_9.booking__ds__extract_month
+ , subq_9.booking__ds__extract_day
+ , subq_9.booking__ds__extract_dow
+ , subq_9.booking__ds__extract_doy
+ , subq_9.booking__ds_partitioned__day
+ , subq_9.booking__ds_partitioned__week
+ , subq_9.booking__ds_partitioned__month
+ , subq_9.booking__ds_partitioned__quarter
+ , subq_9.booking__ds_partitioned__year
+ , subq_9.booking__ds_partitioned__extract_year
+ , subq_9.booking__ds_partitioned__extract_quarter
+ , subq_9.booking__ds_partitioned__extract_month
+ , subq_9.booking__ds_partitioned__extract_day
+ , subq_9.booking__ds_partitioned__extract_dow
+ , subq_9.booking__ds_partitioned__extract_doy
+ , subq_9.booking__paid_at__day
+ , subq_9.booking__paid_at__week
+ , subq_9.booking__paid_at__month
+ , subq_9.booking__paid_at__quarter
+ , subq_9.booking__paid_at__year
+ , subq_9.booking__paid_at__extract_year
+ , subq_9.booking__paid_at__extract_quarter
+ , subq_9.booking__paid_at__extract_month
+ , subq_9.booking__paid_at__extract_day
+ , subq_9.booking__paid_at__extract_dow
+ , subq_9.booking__paid_at__extract_doy
+ , subq_9.ds__day AS metric_time__day
+ , subq_9.ds__week AS metric_time__week
+ , subq_9.ds__month AS metric_time__month
+ , subq_9.ds__quarter AS metric_time__quarter
+ , subq_9.ds__year AS metric_time__year
+ , subq_9.ds__extract_year AS metric_time__extract_year
+ , subq_9.ds__extract_quarter AS metric_time__extract_quarter
+ , subq_9.ds__extract_month AS metric_time__extract_month
+ , subq_9.ds__extract_day AS metric_time__extract_day
+ , subq_9.ds__extract_dow AS metric_time__extract_dow
+ , subq_9.ds__extract_doy AS metric_time__extract_doy
+ , subq_9.listing
+ , subq_9.guest
+ , subq_9.host
+ , subq_9.booking__listing
+ , subq_9.booking__guest
+ , subq_9.booking__host
+ , subq_9.is_instant
+ , subq_9.booking__is_instant
+ , subq_9.bookings
+ , subq_9.instant_bookings
+ , subq_9.booking_value
+ , subq_9.max_booking_value
+ , subq_9.min_booking_value
+ , subq_9.bookers
+ , subq_9.average_booking_value
+ , subq_9.referred_bookings
+ , subq_9.median_booking_value
+ , subq_9.booking_value_p99
+ , subq_9.discrete_booking_value_p99
+ , subq_9.approximate_continuous_booking_value_p99
+ , subq_9.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_10001.booking_value
+ , bookings_source_src_10001.booking_value AS max_booking_value
+ , bookings_source_src_10001.booking_value AS min_booking_value
+ , bookings_source_src_10001.guest_id AS bookers
+ , bookings_source_src_10001.booking_value AS average_booking_value
+ , bookings_source_src_10001.booking_value AS booking_payments
+ , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings
+ , bookings_source_src_10001.booking_value AS median_booking_value
+ , bookings_source_src_10001.booking_value AS booking_value_p99
+ , bookings_source_src_10001.booking_value AS discrete_booking_value_p99
+ , bookings_source_src_10001.booking_value AS approximate_continuous_booking_value_p99
+ , bookings_source_src_10001.booking_value AS approximate_discrete_booking_value_p99
+ , bookings_source_src_10001.is_instant
+ , DATE_TRUNC('day', bookings_source_src_10001.ds) AS ds__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds) AS ds__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds) AS ds__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds) AS ds__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds) AS ds__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds) AS ds__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds) AS ds__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds) AS ds__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds) AS ds__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds) AS ds__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds) AS ds__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.paid_at) AS paid_at__day
+ , DATE_TRUNC('week', bookings_source_src_10001.paid_at) AS paid_at__week
+ , DATE_TRUNC('month', bookings_source_src_10001.paid_at) AS paid_at__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.paid_at) AS paid_at__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.paid_at) AS paid_at__year
+ , EXTRACT(year FROM bookings_source_src_10001.paid_at) AS paid_at__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.paid_at) AS paid_at__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.paid_at) AS paid_at__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.paid_at) AS paid_at__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.paid_at) AS paid_at__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.paid_at) AS paid_at__extract_doy
+ , bookings_source_src_10001.is_instant AS booking__is_instant
+ , DATE_TRUNC('day', bookings_source_src_10001.ds) AS booking__ds__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds) AS booking__ds__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds) AS booking__ds__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds) AS booking__ds__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds) AS booking__ds__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds) AS booking__ds__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds) AS booking__ds__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds) AS booking__ds__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds) AS booking__ds__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds) AS booking__ds__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds) AS booking__ds__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.paid_at) AS booking__paid_at__day
+ , DATE_TRUNC('week', bookings_source_src_10001.paid_at) AS booking__paid_at__week
+ , DATE_TRUNC('month', bookings_source_src_10001.paid_at) AS booking__paid_at__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.paid_at) AS booking__paid_at__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.paid_at) AS booking__paid_at__year
+ , EXTRACT(year FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_doy
+ , bookings_source_src_10001.listing_id AS listing
+ , bookings_source_src_10001.guest_id AS guest
+ , bookings_source_src_10001.host_id AS host
+ , bookings_source_src_10001.listing_id AS booking__listing
+ , bookings_source_src_10001.guest_id AS booking__guest
+ , bookings_source_src_10001.host_id AS booking__host
+ FROM ***************************.fct_bookings bookings_source_src_10001
+ ) subq_9
+ ) subq_10
+ ) subq_11
+ GROUP BY
+ subq_11.metric_time__day
+ ) subq_12
+ ) subq_13
+ ) subq_14
+ ON
+ subq_8.metric_time__day = subq_14.metric_time__day
+ GROUP BY
+ COALESCE(subq_8.metric_time__day, subq_14.metric_time__day)
+) subq_15
diff --git a/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0_optimized.sql b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0_optimized.sql
new file mode 100644
index 0000000000..f9d49b2089
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0_optimized.sql
@@ -0,0 +1,64 @@
+-- Compute Metrics via Expressions
+SELECT
+ metric_time__day
+ , booking_fees - booking_fees_start_of_month AS booking_fees_since_start_of_month
+FROM (
+ -- Combine Metrics
+ SELECT
+ COALESCE(subq_24.metric_time__day, subq_30.metric_time__day) AS metric_time__day
+ , MAX(subq_24.booking_fees_start_of_month) AS booking_fees_start_of_month
+ , MAX(subq_30.booking_fees) AS booking_fees
+ FROM (
+ -- Join to Time Spine Dataset
+ SELECT
+ subq_23.ds AS metric_time__day
+ , subq_21.booking_fees_start_of_month AS booking_fees_start_of_month
+ FROM ***************************.mf_time_spine subq_23
+ INNER JOIN (
+ -- Compute Metrics via Expressions
+ SELECT
+ metric_time__day
+ , booking_value * 0.05 AS booking_fees_start_of_month
+ FROM (
+ -- Read Elements From Semantic Model 'bookings_source'
+ -- Metric Time Dimension 'ds'
+ -- Pass Only Elements:
+ -- ['booking_value', 'metric_time__day']
+ -- Aggregate Measures
+ -- Compute Metrics via Expressions
+ SELECT
+ DATE_TRUNC('day', ds) AS metric_time__day
+ , SUM(booking_value) AS booking_value
+ FROM ***************************.fct_bookings bookings_source_src_10001
+ GROUP BY
+ DATE_TRUNC('day', ds)
+ ) subq_20
+ ) subq_21
+ ON
+ DATE_TRUNC('month', subq_23.ds) = subq_21.metric_time__day
+ ) subq_24
+ FULL OUTER JOIN (
+ -- Compute Metrics via Expressions
+ SELECT
+ metric_time__day
+ , booking_value * 0.05 AS booking_fees
+ FROM (
+ -- Read Elements From Semantic Model 'bookings_source'
+ -- Metric Time Dimension 'ds'
+ -- Pass Only Elements:
+ -- ['booking_value', 'metric_time__day']
+ -- Aggregate Measures
+ -- Compute Metrics via Expressions
+ SELECT
+ DATE_TRUNC('day', ds) AS metric_time__day
+ , SUM(booking_value) AS booking_value
+ FROM ***************************.fct_bookings bookings_source_src_10001
+ GROUP BY
+ DATE_TRUNC('day', ds)
+ ) subq_29
+ ) subq_30
+ ON
+ subq_24.metric_time__day = subq_30.metric_time__day
+ GROUP BY
+ COALESCE(subq_24.metric_time__day, subq_30.metric_time__day)
+) subq_31
diff --git a/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_offsets__plan0.sql b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_offsets__plan0.sql
new file mode 100644
index 0000000000..bc099288f9
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_offsets__plan0.sql
@@ -0,0 +1,340 @@
+-- Compute Metrics via Expressions
+SELECT
+ subq_11.metric_time__day
+ , 2 * bookings_offset_once AS bookings_offset_twice
+FROM (
+ -- Join to Time Spine Dataset
+ SELECT
+ subq_9.metric_time__day AS metric_time__day
+ , subq_8.bookings_offset_once AS bookings_offset_once
+ FROM (
+ -- Date Spine
+ SELECT
+ subq_10.ds AS metric_time__day
+ FROM ***************************.mf_time_spine subq_10
+ ) subq_9
+ INNER JOIN (
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_7.metric_time__day
+ , 2 * bookings AS bookings_offset_once
+ FROM (
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_6.metric_time__day
+ , subq_6.bookings
+ FROM (
+ -- Aggregate Measures
+ SELECT
+ subq_5.metric_time__day
+ , SUM(subq_5.bookings) AS bookings
+ FROM (
+ -- Pass Only Elements:
+ -- ['bookings', 'metric_time__day']
+ SELECT
+ subq_4.metric_time__day
+ , subq_4.bookings
+ FROM (
+ -- Join to Time Spine Dataset
+ SELECT
+ subq_2.metric_time__day AS metric_time__day
+ , 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 (
+ -- Date 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_10001.booking_value
+ , bookings_source_src_10001.booking_value AS max_booking_value
+ , bookings_source_src_10001.booking_value AS min_booking_value
+ , bookings_source_src_10001.guest_id AS bookers
+ , bookings_source_src_10001.booking_value AS average_booking_value
+ , bookings_source_src_10001.booking_value AS booking_payments
+ , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings
+ , bookings_source_src_10001.booking_value AS median_booking_value
+ , bookings_source_src_10001.booking_value AS booking_value_p99
+ , bookings_source_src_10001.booking_value AS discrete_booking_value_p99
+ , bookings_source_src_10001.booking_value AS approximate_continuous_booking_value_p99
+ , bookings_source_src_10001.booking_value AS approximate_discrete_booking_value_p99
+ , bookings_source_src_10001.is_instant
+ , DATE_TRUNC('day', bookings_source_src_10001.ds) AS ds__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds) AS ds__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds) AS ds__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds) AS ds__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds) AS ds__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds) AS ds__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds) AS ds__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds) AS ds__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds) AS ds__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds) AS ds__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds) AS ds__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds_partitioned) AS ds_partitioned__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds_partitioned) AS ds_partitioned__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.paid_at) AS paid_at__day
+ , DATE_TRUNC('week', bookings_source_src_10001.paid_at) AS paid_at__week
+ , DATE_TRUNC('month', bookings_source_src_10001.paid_at) AS paid_at__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.paid_at) AS paid_at__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.paid_at) AS paid_at__year
+ , EXTRACT(year FROM bookings_source_src_10001.paid_at) AS paid_at__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.paid_at) AS paid_at__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.paid_at) AS paid_at__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.paid_at) AS paid_at__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.paid_at) AS paid_at__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.paid_at) AS paid_at__extract_doy
+ , bookings_source_src_10001.is_instant AS booking__is_instant
+ , DATE_TRUNC('day', bookings_source_src_10001.ds) AS booking__ds__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds) AS booking__ds__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds) AS booking__ds__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds) AS booking__ds__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds) AS booking__ds__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds) AS booking__ds__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds) AS booking__ds__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds) AS booking__ds__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds) AS booking__ds__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds) AS booking__ds__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds) AS booking__ds__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__day
+ , DATE_TRUNC('week', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__week
+ , DATE_TRUNC('month', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__year
+ , EXTRACT(year FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.ds_partitioned) AS booking__ds_partitioned__extract_doy
+ , DATE_TRUNC('day', bookings_source_src_10001.paid_at) AS booking__paid_at__day
+ , DATE_TRUNC('week', bookings_source_src_10001.paid_at) AS booking__paid_at__week
+ , DATE_TRUNC('month', bookings_source_src_10001.paid_at) AS booking__paid_at__month
+ , DATE_TRUNC('quarter', bookings_source_src_10001.paid_at) AS booking__paid_at__quarter
+ , DATE_TRUNC('year', bookings_source_src_10001.paid_at) AS booking__paid_at__year
+ , EXTRACT(year FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_year
+ , EXTRACT(quarter FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_quarter
+ , EXTRACT(month FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_month
+ , EXTRACT(day FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_day
+ , EXTRACT(isodow FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_dow
+ , EXTRACT(doy FROM bookings_source_src_10001.paid_at) AS booking__paid_at__extract_doy
+ , bookings_source_src_10001.listing_id AS listing
+ , bookings_source_src_10001.guest_id AS guest
+ , bookings_source_src_10001.host_id AS host
+ , bookings_source_src_10001.listing_id AS booking__listing
+ , bookings_source_src_10001.guest_id AS booking__guest
+ , bookings_source_src_10001.host_id AS booking__host
+ FROM ***************************.fct_bookings bookings_source_src_10001
+ ) subq_0
+ ) subq_1
+ ON
+ subq_2.metric_time__day - INTERVAL 5 day = subq_1.metric_time__day
+ ) subq_4
+ ) subq_5
+ GROUP BY
+ subq_5.metric_time__day
+ ) subq_6
+ ) subq_7
+ ) subq_8
+ ON
+ subq_9.metric_time__day - INTERVAL 5 day = subq_8.metric_time__day
+) subq_11
diff --git a/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_offsets__plan0_optimized.sql b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_offsets__plan0_optimized.sql
new file mode 100644
index 0000000000..d596946dc7
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/DuckDB/test_nested_offsets__plan0_optimized.sql
@@ -0,0 +1,42 @@
+-- Compute Metrics via Expressions
+SELECT
+ metric_time__day
+ , 2 * bookings_offset_once AS bookings_offset_twice
+FROM (
+ -- Join to Time Spine Dataset
+ SELECT
+ subq_22.ds AS metric_time__day
+ , subq_20.bookings_offset_once AS bookings_offset_once
+ FROM ***************************.mf_time_spine subq_22
+ INNER JOIN (
+ -- Compute Metrics via Expressions
+ SELECT
+ metric_time__day
+ , 2 * bookings AS bookings_offset_once
+ FROM (
+ -- Join to Time Spine Dataset
+ -- Pass Only Elements:
+ -- ['bookings', 'metric_time__day']
+ -- Aggregate Measures
+ -- Compute Metrics via Expressions
+ SELECT
+ subq_15.ds AS metric_time__day
+ , SUM(subq_13.bookings) AS bookings
+ FROM ***************************.mf_time_spine subq_15
+ INNER JOIN (
+ -- Read Elements From Semantic Model 'bookings_source'
+ -- Metric Time Dimension 'ds'
+ SELECT
+ DATE_TRUNC('day', ds) AS metric_time__day
+ , 1 AS bookings
+ FROM ***************************.fct_bookings bookings_source_src_10001
+ ) subq_13
+ ON
+ subq_15.ds - INTERVAL 5 day = subq_13.metric_time__day
+ GROUP BY
+ subq_15.ds
+ ) subq_19
+ ) subq_20
+ ON
+ subq_22.ds - INTERVAL 5 day = subq_20.metric_time__day
+) subq_23
diff --git a/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0.xml b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0.xml
new file mode 100644
index 0000000000..c49e1a2f0b
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/test_nested_derived_metric_with_offset_multiple_input_metrics__plan0.xml
@@ -0,0 +1,1741 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/test_nested_offsets__plan0.xml b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/test_nested_offsets__plan0.xml
new file mode 100644
index 0000000000..c9774da39a
--- /dev/null
+++ b/metricflow/test/snapshots/test_dataflow_to_sql_plan.py/SqlQueryPlan/test_nested_offsets__plan0.xml
@@ -0,0 +1,1264 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+