Window(Sum(Sales), CustomerID) AS CustomerTotal
Window() in the load script in Power BI
Qlik's script Window() function adds a partitioned aggregate to each row without collapsing rows, like SQL SUM() OVER (PARTITION BY ...). Power Query has no OVER clause. Use Group By, then merge back, or Group By with an "All rows" step. In most models, the better answer is a measure computed at query time. Use a calculated column only when you really need the value stored per row.
What it does in Qlik
Window(main_expr [, partition1, ...] [, sort_type, sort_expr] [, filter_expr] [, start_expr, end_expr]) computes an aggregate over a partition, optionally ordered and framed for running or sliding windows. It returns a value per input row. It's only available in the load script and costs extra memory and reload time.
Qlik example
Orders:
LOAD *, Window(Sum(Sales), CustomerID) AS CustomerTotal,
Sales / Window(Sum(Sales), CustomerID) AS ShareOfCustomer
RESIDENT RawOrders;Power BI equivalent
Power Query
let
Grouped = Table.Group(Orders, {"CustomerID"}, {
{"CustomerTotal", each List.Sum([Sales]), type number},
{"Rows", each _, type table}}),
Expanded = Table.ExpandTableColumn(Grouped, "Rows", {"OrderID", "OrderDate", "Sales"}),
Share = Table.AddColumn(Expanded, "ShareOfCustomer", each [Sales] / [CustomerTotal], type number)
in
ShareDAX
// calculated column
Customer Total = CALCULATE ( SUM ( Orders[Sales] ), ALLEXCEPT ( Orders, Orders[CustomerID] ) )
// usually better: a measure
Share of customer =
DIVIDE ( [Sales], CALCULATE ( [Sales], REMOVEFILTERS ( Orders ), VALUES ( Orders[CustomerID] ) ) )SQL source query
SELECT o.*, SUM(Sales) OVER (PARTITION BY CustomerID) AS CustomerTotal
FROM dbo.Orders AS o;Gotchas and behaviour differences
- A stored total per row doesn't react to report filters. If a user filters to 2026, the column still shows the all-time total. That's correct for Qlik's script Window() too, but people often expected a chart-level Aggr. See Aggr and TOTAL.
- Group By with "All rows" holds the partition tables in memory and doesn't fold. On large tables, push the window function to SQL instead.
Official documentation
- Window - script function (Qlik Help)
- Table.Group (Power Query M) (Microsoft Learn)
- ALLEXCEPT function (DAX) (Microsoft Learn)
- SELECT - OVER clause (Transact-SQL) (Microsoft Learn)
Related pages
LOAD ..., Sum(x) RESIDENT t GROUP BY ...
Group By in the load script
GROUP BY in a Qlik load pre-aggregates a table. Power Query's Group by (Table.Group) is the direct equivalent. In Power BI you often don't need it at all, because measures aggregate at query time.
Direct equivalent
Avg(Aggr(Sum(Sales), Customer))
Aggr (nested aggregation)
Aggr builds a virtual table of aggregated values, for example sales per customer, so you can aggregate again. In DAX that is an iterator (AVERAGEX, MAXX, COUNTROWS(FILTER(...))) over VALUES or SUMMARIZE that calls a measure.
Partial / different approach
Sum(TOTAL Sales) / Sum(TOTAL <Category> Sales)
The TOTAL qualifier
Qlik's TOTAL qualifier makes an aggregation ignore the chart dimensions but keep the selections. In DAX that is ALLSELECTED. TOTAL <Field> keeps one dimension, which maps to removing only the other dimension columns.
Direct equivalent
RangeSum(Above(Sum(Sales), 0, RowNo()))
Running totals with RangeSum(Above(...))
The Qlik running-total idiom RangeSum(Above(Sum(Sales), 0, RowNo())) maps to a cumulative DAX measure, a WINDOW function, or the RUNNINGSUM visual calculation.
Partial / different approach
Spotted an error or a better pattern? QlikToDax is maintained by a working BI consultant; corrections are welcome via the About page. Last reviewed 2026-10-25.