Skip to content

Preserve Tableau filter order in SQL.

Place a filter at the same stage as the original calculation. This sample filters the visible region while retaining a company-wide denominator.

Updated

Read locally in this browser.

↳sample.csvSynthetic sample

Does filtering to West change the company-wide denominator?

The synthetic dataset totals 1,500: East 600 and West 900. Filtering the displayed rows to West leaves a 60% share when the denominator still includes all regions.

“Show West’s share while keeping all regions in the denominator.”

Worked example · authored synthetic data

  1. Read the original fileUse the existing browser reader
  2. Check the definitionKeep the grouping and filter scope explicit
  3. Compute the resultUse the existing xmetric engine
  4. Review the evidenceRead the exact cells and query

Calculation or query in this example

SELECT Region, SUM(Sales) * 1.0 / (SELECT SUM(Sales) FROM input) AS Share FROM input WHERE Region = 'West' GROUP BY Region

Exact sample file · Definitions and expected values

xmetricWest share of all Revenue

Opening the labelled sample…

Expected values from the labelled sample; the browser recomputes them.

GroupResult
West0.6
Use your own file

Drop one file anywhere on this page. It is read in your browser; no file is uploaded.

Nothing is uploaded.

Read locallyThe original file stays in the browser.

Share deliberatelyMCP shares supported metadata and requested results with the chat host.

Separate actionsOnline saves and support uploads require their own actions.

How does this workflow work?

What is the direct answer to this workbook question?

Tableau evaluates six filter layers at different points in its pipeline, and each layer maps to a specific SQL stage. Context filters become WHERE clauses inside FIXED LOD subqueries, standard dimension filters become outer WHERE clauses before GROUP BY, measure filters map to HAVING, and table calculation filters map to QUALIFY.

Why can moving every filter into WHERE change a result?

When an analyst or AI coding agent translates a Tableau worksheet to SQL, the #1 bug is putting every pill from the Tableau Filters shelf into a single WHERE clause.

In Tableau's order of operations, where a filter sits in the pipeline determines whether it filters rows before or after Level of Detail expressions, standard aggregations, and window calculations.

Where do the filter stages belong in SQL?

Context filters affect the input to FIXED calculations; later filters affect later query stages. The table distinguishes those placements.

Execution Step (First to Last)Tableau Filter / Calculation LayerPill Color in UIExact SQL Equivalent
1. Extract & Data Source FiltersFilters applied when building the extract or data sourceNone (Data Source tab)WHERE clause on the base source table / CTE (base_data).
2. Context FiltersDimension filter with "Add to Context" enabledGrey pillWHERE clause inside the FIXED LOD subquery/CTE (and inherited by all downstream CTEs).
3. FIXED LOD Expressions & Top N / Sets{ FIXED [Dim] : AGG([Measure]) }, Conditional Sets, Top N filtersN/AComputed in a pre-aggregation CTE (fixed_lod_cte) grouped by the FIXED dimensions after Context Filters but before regular Dimension Filters.
4. Regular Dimension FiltersStandard discrete/continuous dimension filters (Region = 'West')Blue pillWHERE clause in the main query after fixed_lod_cte is joined, before the worksheet GROUP BY.
5. INCLUDE / EXCLUDE LODs & Worksheet Aggregation{ INCLUDE ... }, { EXCLUDE ... }, and SUM(), AVG(), COUNTD()Green / BlueComputed after regular Dimension Filters as part of the worksheet's GROUP BY stage.
6. Measure FiltersAggregate filter (SUM([Sales]) >= 10000)Green pillHAVING SUM(sales) >= 10000 on the worksheet GROUP BY query.
7. Table CalculationsRUNNING_SUM(), LOOKUP(), RANK(), WINDOW_AVG()Pill with Δ triangleSQL window functions (OVER (PARTITION BY ... ORDER BY ...)) evaluated after HAVING.
8. Table Calculation FiltersFilter on a table calc (LOOKUP(MIN([Order Month]), 0) or INDEX() <= 5)Pill with Δ triangleQUALIFY clause (in DuckDB, BigQuery, Snowflake) or an outer WHERE wrapping the window CTE.

How can I keep the filter stages in one SQL template?

Suppose a worksheet has:

  • A Context Filter on status = 'Completed' (Step 2)
  • A FIXED LOD computing total regional sales { FIXED [Region] : SUM([Sales]) } (Step 3)
  • A Regular Dimension Filter keeping only category = 'Technology' (Step 4)
  • A Measure Filter requiring SUM([Sales]) > 5000 (Step 6)
  • A Table Calculation computing RUNNING_SUM(SUM([Sales])) (Step 7)
  • A Table Calculation Filter keeping only ranks <= 10 (Step 8)

Here is the exact DuckDB / Snowflake / BigQuery SQL that preserves every stage:

WITH context_filtered AS (
  -- Step 1 & 2: Data Source + Context Filters (Grey Pills)
  SELECT *
  FROM orders
  WHERE status = 'Completed'
),

fixed_lod AS (
  -- Step 3: FIXED LOD computed BEFORE regular dimension filters
  SELECT
    region,
    SUM(sales) AS fixed_region_sales
  FROM context_filtered
  GROUP BY region
),

view_grouped AS (
  -- Step 4, 5 & 6: Dimension Filters (WHERE), View Aggregation (GROUP BY), Measure Filters (HAVING)
  SELECT
    c.region,
    c.state,
    SUM(c.sales) AS tech_state_sales,
    MAX(f.fixed_region_sales) AS total_region_sales_all_categories
  FROM context_filtered c
  JOIN fixed_lod f
    ON c.region = f.region
  WHERE c.category = 'Technology'       -- Step 4: Regular Dimension Filter (Blue Pill)
  GROUP BY c.region, c.state
  HAVING SUM(c.sales) > 5000            -- Step 6: Measure Filter (Green Pill)
),

windowed AS (
  -- Step 7: Table Calculations (Window Functions)
  SELECT
    region,
    state,
    tech_state_sales,
    total_region_sales_all_categories,
    tech_state_sales / total_region_sales_all_categories AS share_of_all_cat_region_sales,
    SUM(tech_state_sales) OVER (
      PARTITION BY region
      ORDER BY tech_state_sales DESC
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_sum_sales,
    RANK() OVER (
      PARTITION BY region
      ORDER BY tech_state_sales DESC
    ) AS sales_rank
  FROM view_grouped
)

-- Step 8: Table Calculation Filter ("Hide without filtering underlying data")
SELECT *
FROM windowed
WHERE sales_rank <= 10;

How can I select a top ten inside a filtered region?

In Tableau, if a user sets a Top 10 Customers by Sales filter and also filters Region = 'East' as a regular blue Dimension Filter, they often see fewer than 10 customers. Why? Because in Tableau's order of operations, Top N filters are not evaluated after regular Dimension Filters—they execute at the Set/Top N stage (or simultaneously with general dimension filters unless ordered via Context), so Region = 'East' does not narrow the pool before the Top 10 are picked unless Region is promoted to a Context Filter.

In Tableau, you fix this by clicking "Add to Context" on Region. In SQL, you fix it by placing WHERE region = 'East' inside the CTE before computing RANK() OVER (ORDER BY SUM(sales) DESC).

Why do analysts use `LOOKUP(MIN([Order Date]), 0)` as a filter in Tableau?

Wrapping a dimension in LOOKUP(..., 0) turns it into a Table Calculation Filter (Step 8). That lets you hide earlier months from the visual chart without removing those rows from a RUNNING_SUM or Year-over-Year LOOKUP(..., -12) window calculation. In SQL, compute LAG() or SUM() OVER() in a CTE first, then filter order_date in the outer SELECT.

How can I check which filters on a .twbx worksheet are Context Filters?

Drop the .twbx or .twb file into the xmetric workbook inspector in your browser to see the fields on each sheet's shelves, or inspect filter class='categorical' column='...' context='true' in the worksheet XML.

Can I test filter order of operations with LODs in xmetric?

Yes. You can run Level of Detail expressions (FIXED, INCLUDE, EXCLUDE) and table calculations on sample data in the formula playground and see the equivalent SQL for the LOD and filter steps, free in your browser. To test a full worksheet, import a CSV, Excel, or Parquet file into the xmetric app and put fields on the Rows, Columns, and Filters shelves.

Run the LOD in the formula playground, then check the filter stages on a real view in the xmetric app.

What data does this worked example use?

The initial view uses authored synthetic data, not customer data or a captured agent session.

The example record lists its file, calculation or SQL and expected values. The live browser result is computed by xmetric’s existing engine or workbook inspector. Samples are excluded from own-data activation reporting.