Thank you for the previous clarifications regarding incremental refresh and fallback behavior. I have a few follow-up questions to better understand how Materialized Views behave in practice.

1. Full refresh semantics

Does a full refresh of a Materialized View always replace the entire target table, or does it merge results with what already exists?
Consider the following example:
CREATE MATERIALIZED VIEW mv_monthly_median AS
SELECT
customer_id,
date_trunc('month', timestamp) AS month,
percentile_approx(value, 0.5) AS median_value
FROM time_series_table
WHERE date_trunc('month', timestamp) >=
add_months(date_trunc('month', current_date()), -12)
GROUP BY
customer_id,
date_trunc('month', timestamp);


This computes the monthly median per customer for the last 12 months.

Suppose:

I run this today for the first time. Then I run it again 2 months later. Which of the following behaviors is correct?

1. A full refresh recomputes the last 12 months and merges them with existing results -> final table contains 14 months.
2. A full refresh recomputes the last 12 months and replaces all existing data -> final table contains 12 months.
3. An incremental refresh computes only the 2 new months and merges them -> final table contains 14 months.
4. An incremental refresh computes only the 2 new months and also deletes months now outside the 12-month window -> final table contains 12 months.

My understanding is that option 4 is what happens, since the MV reflects exactly the query definition and not accumulated history. Could you confirm?

If the desired behavior is option 3 (i.e., accumulate historical results beyond the rolling window), would the recommended approach be:
1. Create the MV with the rolling window logic
2. Then have a downstream table that merges new/updated rows from the MV into a historical results table

Is this the intended pattern?


2. Best practices for defining and deploying Materialized Views

- Are MVs SQL-only, or can they be defined using Python?
- If SQL-only, is it correct that Python UDF logic must be wrapped and called from SQL? Is it recommended to manage MVs using Databricks Asset Bundles for a dev/qas/prod setup?
- If definition via python is allowed, how should those MV be deployed?
- What is considered best practice for deploying MVs in production? Specifically:
- When a MV is redeployed (with the same name), is it effectively dropped and recreated, with its history dropped?
- OR does replacing an MV via deployment preserve its refresh state/history? If so:
- If I redeploy the same MV definition with no meaningful changes, does that trigger a full refresh?
- If I change something trivial (e.g., formatting or alias), does it force recomputation?
- If I change the filter window (see example below), does Databricks:
- Fully recompute everything?
- Or incrementally compute only the newly included time range?

Original example:
WHERE date_trunc('month', timestamp) >=
add_months(date_trunc('month', current_date()), -12)

New deployment:
WHERE date_trunc('month', timestamp) >=
add_months(date_trunc('month', current_date()), -16)


Would this cause:
- A full refresh?
- Or an incremental refresh that recomputes only the additional 4 months?

I am trying to understand how stable MV lifecycle management is in a CI/CD setup and how refresh behavior interacts with redeployments.

Thank you!