Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Write, execute, and optimize DAX queries and measures for Power BI semantic models using pbi-cli. Invoke this skill whenever the user mentions DAX, queries data in Power BI, writes calculations, creates measures, asks about EVALUATE, SUMMARIZECOLUMNS, CALCULATE, time intelligence, or wants to analyze/aggregate data from a semantic model. Also invoke when the user asks to run a query, test a formula, or check row counts. This skill contains critical guidance on passing DAX expressions via CLI arg
.claude/skills/minasaad1-power-bi-dax/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -26% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -26% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 6% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 9% | 0% |
Execute and validate DAX queries against connected Power BI models.
bashpipx install pbi-cli-tool pbi-cli skills install pbi connect
bash# Inline query pbi dax execute "EVALUATE TOPN(10, Sales)" # From file pbi dax execute --file query.dax # From stdin (piping) cat query.dax | pbi dax execute - echo "EVALUATE Sales" | pbi dax execute - # With options pbi dax execute "EVALUATE Sales" --max-rows 100 pbi dax execute "EVALUATE Sales" --timeout 300 # Custom timeout (seconds) # JSON output for scripting pbi --json dax execute "EVALUATE Sales"
When passing DAX as a -e argument, the shell collapses newlines into a single line. Simple expressions like SUM(Sales[Amount]) work fine, but multi-line DAX using VAR/RETURN breaks because the DAX parser needs line breaks between those keywords.
Why this matters: A measure like VAR x = [Total Sales] VAR y = [Sales PY] RETURN DIVIDE(x - y, y) will fail with a syntax error because the engine sees it as one continuous line without statement separators.
Workarounds (pick one):
bash# Option 1: Pipe from stdin (recommended for measures) echo 'VAR TotalSales = SUM(Sales[Amount]) VAR TotalCost = SUM(Sales[Cost]) RETURN TotalSales - TotalCost' | pbi measure create "Profit" -e - -t Sales # Option 2: Write to a .dax file and use --file (for queries) echo 'EVALUATE ROW("Result", VAR x = SUM(Sales[Amount]) RETURN x )' > query.dax pbi dax execute --file query.dax
Single-line alternatives (preferred when possible):
For simple ratio/growth measures, use inline patterns instead of VAR/RETURN:
bash# Instead of: VAR x = SUM(...) / VAR y = SUM(...) / RETURN DIVIDE(x, y) # Use inline DIVIDE -- it handles division-by-zero gracefully (returns BLANK): pbi measure create "Margin %" \ -e "DIVIDE(SUM(Sales[Amount]) - SUM(Sales[Cost]), SUM(Sales[Amount]))" \ -t Sales --format-string "0.0%" # Instead of: VAR current = [Total Sales] / VAR prev = [Sales PY] / RETURN DIVIDE(...) # Reference measures directly in DIVIDE: pbi measure create "YoY %" \ -e "DIVIDE([Total Sales] - [PY Sales], [PY Sales])" \ -t Sales --format-string "0.0%"
bashpbi dax validate "EVALUATE Sales" pbi dax validate --file query.dax
bashpbi dax clear-cache # Clear the formula engine cache
bash# Simple aggregation pbi measure create "Total Sales" -e "SUM(Sales[Amount])" -t Sales # Time intelligence pbi measure create "YTD Sales" -e "TOTALYTD(SUM(Sales[Amount]), Calendar[Date])" -t Sales # Previous year comparison pbi measure create "PY Sales" -e "CALCULATE([Total Sales], SAMEPERIODLASTYEAR(Calendar[Date]))" -t Sales # Year-over-year change pbi measure create "YoY %" -e "DIVIDE([Total Sales] - [PY Sales], [PY Sales])" -t Sales --format-string "0.0%"
bash# List all tables pbi dax execute "EVALUATE INFO.TABLES()" # List columns in a table pbi dax execute "EVALUATE INFO.COLUMNS()" # Preview table data pbi dax execute "EVALUATE TOPN(10, Sales)" # Count rows pbi dax execute "EVALUATE ROW(\"Count\", COUNTROWS(Sales))"
bash# Basic sum pbi dax execute "EVALUATE ROW(\"Total\", SUM(Sales[Amount]))" # Group by with aggregation pbi dax execute "EVALUATE SUMMARIZECOLUMNS(Products[Category], \"Total\", SUM(Sales[Amount]))" # Multiple aggregations pbi dax execute " EVALUATE SUMMARIZECOLUMNS( Products[Category], \"Total Sales\", SUM(Sales[Amount]), \"Avg Price\", AVERAGE(Sales[UnitPrice]), \"Count\", COUNTROWS(Sales) ) "
bash# CALCULATE with filter pbi dax execute " EVALUATE ROW(\"Online Sales\", CALCULATE(SUM(Sales[Amount]), Sales[Channel] = \"Online\")) " # FILTER with complex condition pbi dax execute " EVALUATE FILTER( SUMMARIZECOLUMNS(Products[Name], \"Total\", SUM(Sales[Amount])), [Total] > 1000 ) "
bash# Year-to-date pbi dax execute " EVALUATE ROW(\"YTD\", TOTALYTD(SUM(Sales[Amount]), Calendar[Date])) " # Rolling 12 months pbi dax execute " EVALUATE ROW(\"R12\", CALCULATE( SUM(Sales[Amount]), DATESINPERIOD(Calendar[Date], MAX(Calendar[Date]), -12, MONTH) )) "
bash# Top products by sales pbi dax execute " EVALUATE TOPN( 10, ADDCOLUMNS( VALUES(Products[Name]), \"Total\", CALCULATE(SUM(Sales[Amount])) ), [Total], DESC ) "
--max-rows to limit result sets during developmentpbi dax clear-cache before benchmarkingSUMMARIZECOLUMNS over SUMMARIZE for groupingCALCULATE with simple filters instead of nested FILTERSUMX, FILTER) on large tables when aggregations suffice| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 6,571 | 2,781 | -58% | 1 | 1 | 0% | 1,375 | 2,102 | +53% | 0 | 0 | — |
case-02 | fail→pass | 13,706 | 2,036 | -85% | 1 | 1 | 0% | 2,590 | 1,921 | -26% | 0 | 0 | — |
case-03 | fail→pass | 25,155 | 2,551 | -90% | 1 | 1 | 0% | 2,658 | 1,968 | -26% | 0 | 0 | — |
case-04 | fail→pass | 13,419 | 5,302 | -60% | 1 | 1 | 0% | 2,530 | 2,670 | +6% | 0 | 0 | — |
case-05 | fail→pass | 10,743 | 2,654 | -75% | 1 | 1 | 0% | 1,839 | 2,005 | +9% | 0 | 0 | — |
case-06 | fail→pass | 12,570 | 2,249 | -82% | 1 | 1 | 0% | 2,207 | 1,929 | -13% | 0 | 0 | — |
case-07 | pass→pass | 15,428 | 2,117 | -86% | 1 | 1 | 0% | 1,459 | 1,843 | +26% | 0 | 0 | — |
case-08 | pass→pass | 11,520 | 2,292 | -80% | 1 | 1 | 0% | 1,962 | 1,938 | -1% | 0 | 0 | — |
case-09 | pass→pass | 6,277 | 1,914 | -70% | 1 | 1 | 0% | 1,248 | 1,887 | +51% | 0 | 0 | — |
case-10 | pass→pass | 9,089 | 3,080 | -66% | 1 | 1 | 0% | 1,815 | 2,065 | +14% | 0 | 0 | — |
case-11 | fail→pass | 15,005 | 2,821 | -81% | 1 | 1 | 0% | 2,497 | 2,039 | -18% | 0 | 0 | — |
case-12 | fail→pass | 12,622 | 2,763 | -78% | 1 | 1 | 0% | 2,236 | 2,120 | -5% | 0 | 0 | — |
case-13 | pass→pass | 7,657 | 5,331 | -30% | 1 | 1 | 0% | 1,386 | 2,579 | +86% | 0 | 0 | — |
case-14 | pass→pass | 7,006 | 4,452 | -36% | 1 | 1 | 0% | 1,339 | 2,349 | +75% | 0 | 0 | — |
case-15 | pass→pass | 7,901 | 5,368 | -32% | 1 | 1 | 0% | 1,280 | 2,427 | +90% | 0 | 0 | — |
case-16 | fail→pass | 6,292 | 2,044 | -68% | 1 | 1 | 0% | 1,026 | 1,856 | +81% | 0 | 0 | — |
case-17 | pass→pass | 8,596 | 4,053 | -53% | 1 | 1 | 0% | 1,464 | 2,195 | +50% | 0 | 0 | — |
case-18 | pass→pass | 14,745 | 10,186 | -31% | 1 | 1 | 0% | 2,465 | 3,175 | +29% | 0 | 0 | — |
case-19 | pass→pass | 12,129 | 9,512 | -22% | 1 | 1 | 0% | 2,044 | 3,040 | +49% | 0 | 0 | — |
case-20 | fail→fail | 14,608 | 5,578 | -62% | 1 | 1 | 0% | 2,153 | 2,376 | +10% | 0 | 0 | — |
case-21 | fail→fail | 9,938 | 5,851 | -41% | 1 | 1 | 0% | 1,764 | 2,773 | +57% | 0 | 0 | — |
case-22 | fail→pass | 16,347 | 11,096 | -32% | 1 | 1 | 0% | 2,786 | 3,374 | +21% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +45 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.