# Tableau Table Calculations in Databricks AI/BI: Running Totals, Ranks, and Window Functions

> Map RUNNING_SUM, WINDOW_AVG, RANK, LOOKUP and percent of total to Databricks AI/BI custom calculations and SQL window functions, and see where each runs.

- Canonical: https://getantares.io/tableau-table-calculations-to-databricks/
- Published: 2026-09-08
- Updated: 2026-09-08

---

In Databricks AI/BI, a Tableau table calculation has two possible homes, computing at different moments. A calculated measure written with `AGGREGATE OVER` runs after the visualization groups its data. A window function written into the dataset SQL runs before dashboard field filters reach the result. Choosing the wrong home is the usual reason a converted total stops matching.

## Where a table calculation runs in Databricks AI/BI

Tableau states the rule plainly: a table calculation "computes on the local data", and table calculations "do not consider any measures or dimensions that are filtered out of the visualization", per Tableau's [documentation](https://help.tableau.com/current/pro/desktop/en-us/calculations_tablecalculations.htm). The marks left in the view are the input.

The [custom calculations page](https://docs.databricks.com/aws/en/dashboards/manage/data-modeling/custom-calculations/) splits that in two. Scalar window functions use `OVER` and aggregate "before being joined back to the untransformed underlying table as a dimension". Aggregate window functions use `AGGREGATE OVER` and "compute windowed aggregations after visualization grouping has been applied".

With the dataset query, that makes three places for the arithmetic. Databricks points `AGGREGATE OVER` at calculations that should respect visualization filters, and the scalar `OVER` form at calculations "that must ignore all visualization groupings and filters". The third differs again: a window written into [dataset SQL](https://docs.databricks.com/aws/en/dashboards/manage/data-modeling/datasets) has already run when a field filter arrives, while a parameter substituted into that query changes what the window sees. Which control to reach for is on [parameters in Databricks AI/BI](/tableau-parameters-to-databricks-ai-bi-parameters/). The docs do not cover every combination, so tie one number out at two filter states.

| Tableau | AI/BI custom calculation | Dataset SQL alternative |
| --- | --- | --- |
| `RUNNING_SUM(SUM([Sales]))` | `SUM(Sales) AGGREGATE OVER (ORDER BY Date CUMULATIVE)` | `SUM(sales) OVER (ORDER BY Date RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)` |
| `WINDOW_AVG(SUM([Sales]), -2, 0)` | No direct equivalent: divide a windowed `SUM` by the number of periods | `AVG(daily_sales) OVER (ORDER BY day ROWS 2 PRECEDING)` |
| `TOTAL(SUM([Sales]))` | `SUM(Sales) AGGREGATE OVER (PARTITION BY * EXCEPT (Product))`, the `EXCEPT` list being whatever Compute Using totalled over; `AGGREGATE OVER (ORDER BY Date ALL)` is the other documented total | `SUM(sales) OVER (PARTITION BY Region)` |
| `SUM([Sales]) / TOTAL(SUM([Sales]))`, the Percent of Total quick table calculation | `SUM(Sales) / (SUM(Sales) AGGREGATE OVER (PARTITION BY * EXCEPT (Region)))` | `SUM(Sales) / SUM(SUM(Sales)) OVER ()` |
| `LOOKUP(SUM([Sales]), -1)` | No offset function; a one-period `TRAILING` range gives the previous period's aggregate | `LAG(sales) OVER (ORDER BY Date)` |
| `RANK`, `RANK_DENSE` | `RANK()` and `DENSE_RANK()`, ranking rows rather than marks | Rank a pre-aggregated query |
| Top N on a table calculation | Not documented | `QUALIFY RANK() OVER (PARTITION BY Region ORDER BY Sales DESC) = 1` |

## How running totals and moving windows convert

Running totals convert almost mechanically. Databricks documents `CUMULATIVE` as the equivalent of `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`, current mark included, as in Tableau's `RUNNING_SUM`.

Moving windows are where numbers drift. `WINDOW_AVG(SUM([Sales]), -2, 0)` averages three already aggregated marks. `TRAILING` and `LEADING` count time instead, in units of `DAY`, `MONTH` or `YEAR`, and they default to `EXCLUSIVE`, so add `INCLUSIVE` wherever the Tableau window ended at `0`. Check what a gap does too: a mark-counted window steps over an empty period and a time-counted window counts it, the tolerance Databricks gives as the reason to prefer the time form.

One correction matters more than the syntax. `AGGREGATE OVER` re-evaluates the aggregate over every row in its frame, so `AVG(Sales)` across a trailing range returns the row-level mean, not the mean of the daily totals Tableau was averaging. Divide a windowed `SUM` by the number of periods instead, or pre-aggregate to one row per day in the dataset query and average that with a [window frame](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-window-functions-frame) such as `ROWS 2 PRECEDING`, which ends at the current row. An `OFFSET` clause shifts a whole range, so `TRAILING 7 DAY OFFSET -1 YEAR` reads a year back.

## How ranks, LOOKUP and percent of total convert

Ranking needs the most care, because Tableau ranks the marks and the AI/BI ranking functions do not. All ranking and analytic window functions are supported in custom calculations, per the [function reference](https://docs.databricks.com/aws/en/dashboards/manage/data-modeling/custom-calculations/function-reference), but they belong to the scalar `OVER` family that computes before grouping. Ranking what a viewer sees means ranking an already aggregated result in dataset SQL.

Direction is the second trap, and it inverts a leaderboard without erroring. Tableau's `RANK` and `RANK_DENSE` default to descending, so the largest value ranks 1, while the example in Databricks' [QUALIFY reference](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-qry-select-qualify) ranks the smallest quantity 1. Add `DESC` to match. `RANK_PERCENTILE` defaults to ascending, lowest value at 0.

The documented percent-of-total pattern is `SUM(Sales) / (SUM(Sales) AGGREGATE OVER (PARTITION BY * EXCEPT (Region)))`. The nested form `SUM(Sales) / SUM(SUM(Sales)) OVER ()` also works for decomposable aggregates, though Databricks warns against it in a pivot table, where values get counted twice. `LOOKUP` with a negative offset has two answers: `LAG` at row level, or a one-period `TRAILING` range for an aggregated mark.

## Why partitioning and addressing become PARTITION BY

Tableau gives every dimension in the view one of two jobs. "Partitioning fields break the view up into multiple sub-views", and the remaining addressing fields "determine the direction of the calculation". None of it lives in the formula text, and in AI/BI the partition is inherited rather than declared.

| Tableau setting | What it controls | Databricks AI/BI |
| --- | --- | --- |
| Addressing (Compute Using) | The direction the calculation moves | `ORDER BY` inside `AGGREGATE OVER` or `OVER` |
| Partitioning (Restarting every) | Where the calculation resets | The visualization grouping picked up by `PARTITION BY *` |

Two limits bound custom calculations, as of September 2026. The [custom calculations page](https://docs.databricks.com/aws/en/dashboards/manage/data-modeling/custom-calculations/) caps them at 200 per dataset and notes that table visualizations take calculated dimensions but not calculated measures. The [dashboard limits page](https://docs.databricks.com/aws/en/dashboards/limits) puts chart rendering at 15,000 rows and tables at 100,000 rows before truncation; the visualization types page gives a lower table figure, so treat 100,000 as the ceiling and test.

## What Antares does with table calculations

Addressing settings are the reason a table-calculation inventory cannot be built with a text search, and that is where a BI migration tool earns its keep on this route: the free Analyzer is deterministic, reads workbook metadata only, and lists which workbooks carry table calculations.

Where a partition cannot be resolved from the workbook, the Converter flags it for a person instead of guessing, because a guessed partition returns a plausible wrong number rather than an error. It is deterministic-first, with guardrailed and validated AI steps that can run against your own private LLM endpoints. Nothing in the Tableau environment changes. [Try a sample conversion](https://try.getantares.io) on a dashboard you know well.

Two neighbors finish the story: [LOD expressions in Databricks SQL](/tableau-lod-expressions-to-databricks-sql/) for pinned grains, and [calculated fields to Databricks SQL](/tableau-calculated-fields-to-databricks-sql/) for row-level formulas. Sequencing is on the [migration guide](/tableau-to-databricks-ai-bi-migration/), and the DAX version of this mapping is [Tableau table calculations to DAX](/tableau-table-calculations-to-dax/). Sources: Databricks' [custom calculations](https://docs.databricks.com/aws/en/dashboards/manage/data-modeling/custom-calculations/), [level of detail](https://docs.databricks.com/aws/en/dashboards/manage/data-modeling/custom-calculations/level-of-detail) and [window functions](https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-window-functions) pages, and Tableau's [table calculation functions](https://help.tableau.com/current/pro/desktop/en-us/functions_functions_tablecalculation.htm).

## Related resources

- [Tableau to Databricks AI/BI Migration](/tableau-to-databricks-ai-bi-migration/)
- [LOD Expressions to Databricks SQL](/tableau-lod-expressions-to-databricks-sql/)
- [Calculated Fields to Databricks SQL](/tableau-calculated-fields-to-databricks-sql/)
- [Table Calculations to DAX](/tableau-table-calculations-to-dax/)

## FAQ

### What is the Databricks equivalent of RUNNING_SUM?

A calculated measure using the CUMULATIVE frame keyword: SUM(Sales) AGGREGATE OVER (ORDER BY Date CUMULATIVE). Databricks documents CUMULATIVE as the equivalent of RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, so the current mark is included, as it is in Tableau. The same frame works in dataset SQL, but it computes before dashboard field filters apply.

### How do you write a moving average like WINDOW_AVG in Databricks AI/BI?

Not as a single keyword. WINDOW_AVG(SUM([Sales]), -2, 0) averages three already aggregated marks, while AGGREGATE OVER re-evaluates the aggregate across every row in its frame. Divide a windowed SUM by the number of periods, or pre-aggregate to one row per day in the dataset query and average that with a ROWS frame. TRAILING and LEADING also count time rather than marks and default to EXCLUSIVE.

### Do Databricks AI/BI window calculations respect dashboard filters?

It depends on the syntax. Databricks recommends AGGREGATE OVER for window calculations that respect visualization filters, and the scalar OVER form for calculations that must ignore all visualization groupings and filters. A window inside dataset SQL runs before a field filter reaches it, though a parameter substituted into that query does change the result.

### What replaces Tableau's Compute Using setting in Databricks AI/BI?

The visualization's own grouping, read through PARTITION BY * with an EXCEPT list, plus ORDER BY for direction. Tableau's addressing and partitioning choices live in the worksheet rather than the formula text, so plan on opening each workbook instead of counting formulas when you scope this work.
