OpenBI Docs Buy

OAX and DAX

OAX, Open Analytical Expressions, is the language of OpenBI’s own engine. It takes DAX as its reference, so Power BI and Analysis Services models and their measures work in OpenBI as they are, and it adds functions DAX doesn’t have. This page is for analysts and IT.

What OAX is

DAX is the language of Microsoft’s Power BI and Analysis Services, run by Microsoft’s engine. OpenBI has an engine of its own, written in C, and its language is OAX. OAX uses DAX as its reference: the same syntax, the same functions under the same names, the same filter and row contexts. OpenBI’s conformance tests check its answers against Power BI Desktop’s, case by case, with Power BI Desktop as the benchmark.

On top of DAX’s functions, OAX has functions of OpenBI’s own: survival analysis, predictions and forecasts, optimisation, quantitative finance, networks, statistics as tables, images and more. OAX functions lists every function, with OpenBI’s own marked OpenBI.

What works as it is

Models from Power BI and Analysis Services
Imported from an open Power BI Desktop, a .pbip, .pbit or .bim file, a TMDL folder or an Excel data model: their measures, calculated columns, calculation groups and roles’ row filters run in OAX unchanged. See Import from Power BI.
Power BI projects kept in Power BI
A .pbip you keep working in Power BI Desktop stays Power BI’s: a measure written in OpenBI works in both, as long as it uses DAX’s functions only. OpenBI’s own functions are for OpenBI projects.
Live connections
On a model that lives on Analysis Services, Power BI or Fabric, the server’s own engine answers each query, in its DAX, and your own measures go with the queries OpenBI sends it. Most of OpenBI’s own functions work there too: the server computes the rows they read, and OpenBI runs the function on them. See Live connections.
Older servers
A server of an older version lacks newer DAX: SQL Server 2016 Analysis Services has no TREATAS, IN or table constructor ({ }). OpenBI’s report pages notice the first refusal and ask such a server the older way.
Measures and queries
Measures, calculated columns and row filters are OAX, and so are queries, written as DAX writes them: EVALUATE, DEFINE with MEASURE, VAR, COLUMN and TABLE, ORDER BY and START AT. The OAX view runs them (see OAX queries and performance), and agents run them with dax_query.
Dates and times
A date-time is held as Power BI Desktop holds it, to 1/300 of a second: a value loaded from a source, and one an expression of constants works out, so date-time arithmetic, filters on columns with fractions of a second and FORMAT give Desktop’s answers, and the studio’s grids show the fractions. NOW, TODAY, UTCNOW and UTCTODAY read the clock once for the whole query; UTCNOW and UTCTODAY in UTC.
Excel
Analyze in Excel connects Excel’s PivotTables to OpenBI’s engine as to Analysis Services, in the studio and on OpenBI Server. Excel asks in MDX, and OpenBI answers with OAX queries over the model, so its measures work in Excel as in Power BI. See Excel in the studio and Excel connections on the server.

What OAX adds

OpenBI Studio 0.3.74 has 69 functions of OpenBI’s own. A measure that uses one works in OpenBI only: Power BI and Analysis Services don’t have them. By family, with a few of each:

FamilySome of its functions
Survival analysisSURVIVAL.CURVE, SURVIVAL.TEST, SURVIVAL.COX, SURVIVAL.COX.PREDICT: how long until an event, as R’s survival package computes it
Predictions and forecastsPREDICT: the scores, or the forecast, of a prediction trained in the studio (see Prediction)
Operations researchOPTIMIZE, OPTIMIZE.VALUE, ROUTES, SCHEDULE: plans solved again for a what-if, vehicle routes and schedules
Quantitative financeQUANT.BOND.PRICE, QUANT.OPTION.PRICE, QUANT.CURVE, VALUATION, MONTECARLO: bonds, options, curves and simulations with QuantLib
NetworksNETWORK.NODES, NETWORK.COMMUNITIES, NETWORK.PATH, NETWORK.CYCLES: the network the rows in view make
Many variables at oncePCA.COMPONENTS, KMEANS, UMAP: principal components, clusters and maps of the rows
Statistics as tablesDECOMPOSE, HISTOGRAM, BOXPLOT, TRENDLINE, CORREL: a series’ trend and season, distributions, trend lines with their bands
Images and coloursIMAGECOLORS, IMAGECOLOR, COLORNAME: the colours of a picture, and a colour’s name

Where the studio still says DAX

OpenBI Studio says OAX wherever it names OpenBI’s language: the OAX view and OAX query on the ribbon, Format OAX on the Measure tools tab, the formula bar, notebooks’ OAX steps, filters’ OAX conditions and a visual’s Show OAX. It says DAX where it means Microsoft’s: a live server’s own measures and queries, the Analysis Services source, and SQLBI’s DAX Studio and DAX Formatter. The tools agents use keep their names, dax_query, dax_show, dax_compare, dax_benchmark and dax_format, because agents know DAX; they all take OAX, DAX’s functions and OpenBI’s alike. Where these pages name a label or a tool, they use its real name.

Known differences

Where Power BI Desktop and an older Analysis Services answer differently, OpenBI answers as Power BI Desktop. The differences its tests record, on a model OpenBI’s engine runs (on a live connection the server answers, with its own behaviour):

WhatOpenBIPower BI and Analysis Services
Fixed decimal (Currency) arithmeticEach row’s result rounded to four decimals, as DAX’s rules say: Power BI Desktop’s answer when its formula engine computes it.Desktop’s storage engine may round otherwise, depending on the query, so a total can differ in its last decimals. Sum first and then multiply, or CONVERT to DOUBLE, and both agree.
Sums of decimal numbersA sum that comes to zero is zero.Analysis Services can leave a tiny residue, such as 2-39, so a test for zero can differ.
Two-digit years in DATE, and the year 100As Power BI Desktop: DATE(49, 1, 1) is in 2049, DATE(100, 1, 1) in the year 100.SQL Server 2016 Analysis Services adds 1900 to every year below 1900.
APPROXIMATEDISTINCTCOUNTThe exact distinct count.Power BI refuses it on an imported model: it estimates, for DirectQuery sources.
HASHA 64-bit hash with the same properties.Power BI’s algorithm isn’t published, so its numbers differ.
EVALUATEANDLOGReturns its value; writes no log.Power BI Desktop also logs the value, for tracing.
SAMPLEAXISWITHLOCALMINMAX, SAMPLECARTESIANPOINTSBYCOVERThe whole table up to the size asked; past it, OpenBI’s own bins.Power BI Desktop’s bins past the size aren’t published, so its samples may differ.
USERNAME, USEROBJECTIDThe same text as USERPRINCIPALNAME: the user the query runs as (on OpenBI Server, the person’s e-mail).Each its own form of the user’s identity.
Date-times worked out from constantsAs Power BI Desktop: held to 1/300 of a second, so (DATE(2026, 11, 2) + TIME(9, 55, 26)) - (DATE(2026, 11, 2) + TIME(8, 55, 26)) is exactly 1/24, and 24 times it is 1.SQL Server 2016 Analysis Services doesn’t round them, and answers 0.99999999994.

Differences kept on purpose

A few queries Power BI Desktop refuses, or answers in an order it doesn’t say, have a well-defined answer. OpenBI gives it, on purpose:

WhatOpenBIPower BI Desktop
TOPNSKIP with a skipSorts the rows and skips as many as asked, over any table and by any number of order columns.Skips rows only over a model table ordered by one column; over a variable’s rows or VALUES, or ordered by two columns, it refuses the query.
LOOKUP’s INFERREDRead as EXPLICIT, the default.INFERRED also clears the filters of the columns the visual sorts and groups the search columns by. In every visual shape tried, Power BI Desktop answered the same both ways.
CONCATENATEX without an orderA column’s values from the smallest, a table’s rows as they were loaded.The order its storage keeps them in, which follows the data only in part and can’t be told from the model. Give CONCATENATEX an order, its fourth argument, whenever the order matters: then both agree.
A TRUE/FALSE filter in SUMMARIZECOLUMNSAn OAX convenience, read as CALCULATE reads one: SUMMARIZECOLUMNS ( Products[Category], Products[Product] = "Pils", "Liters", [Liters sold] ) filters with FILTER ( ALL ( Products[Product] ), Products[Product] = "Pils" ). On a live connection, OpenBI sends the server that FILTER form.Refuses a TRUE/FALSE expression as a filter of SUMMARIZECOLUMNS. In a measure or query that must run in Power BI too, write the FILTER ( ALL ( … ), … ) form yourself.
PATH over a parent that is no row’s idThe parent is taken as the top, and the path begins with it: x|d for a row d whose parent x is no row’s id. The model loads, with a warning that names the column and its first such rows; on OpenBI Server, the refresh’s history says so too.Refuses such a model: its refresh fails until the parent is put right.

Refused, as in Power BI

Where Power BI Desktop refuses a query because its answer would contradict the function’s own definition, OpenBI refuses it too, with an error that says what to change:

  • KEEPFILTERS only where Power BI Desktop takes it: in CALCULATE’s and CALCULATETABLE’s filters, and around the table an iterator goes through, such as SUMX ( KEEPFILTERS ( ALL ( Products[Product] ) ), [Liters sold] ). Used as a table on its own, in EVALUATE, a variable or COUNTROWS, it is an error.
  • NONVISUAL on a column the SUMMARIZECOLUMNS doesn’t group by is an error: such a filter would change the values, which NONVISUAL says it doesn’t.
  • USERELATIONSHIP only among CALCULATE’s and CALCULATETABLE’s filters, as itself: inside another function it is an error.

A report whose visual sends such a query shows that visual’s error instead of a number. Each function’s page shows its refusals as examples.

Last updated · OpenBI Studio 0.3.74