power-bi-dax
Writes correct, fast DAX measures with proper filter context, time intelligence on a marked date table, and VertiPaq-friendly patterns, diagnosing slow visuals down to the storage-vs-formula engine split. Use when someone asks "why does my DAX measure return the wrong total", "write a YTD or year-over-year measure", "my Power BI report is slow", "CALCULATE isn't doing what I expect", or "measure vs calculated column". Do NOT use for Tableau calculated fields and dashboard design - use tableau-best-practices instead; for writing warehouse SQL and turning query results into findings - use sql-to-insights instead; for Excel or Google Sheets financial models - use spreadsheet-model-builder instead.
- License 许可
- MIT
- 最近更新
- 2026-10-14
- Stars
- ★ 25
- Forks
- 3
01 前言 Front Matter
- name
- power-bi-dax
- metadata
- { "title": "Power BI DAX" }
- description
- Writes correct, fast DAX measures with proper filter context, time intelligence on a marked date table, and VertiPaq-friendly patterns, diagnosing slow visuals down to the storage-vs-formula engine split. Use when someone asks "why does my DAX measure return the wrong total", "write a YTD or year-over-year measure", "my Power BI report is slow", "CALCULATE isn't doing what I expect", or "measure vs calculated column". Do NOT use for Tableau calculated fields and dashboard design - use tableau-best-practices instead; for writing warehouse SQL and turning query results into findings - use sql-to-insights instead; for Excel or Google Sheets financial models - use spreadsheet-model-builder instead.
03 SKILL.md 正文
Power BI DAX
DAX fails quietly: a measure that returns plausible numbers under one slicer combination and wrong ones under another, or a report that takes 20 seconds because one measure iterates a fact table row by row. This skill produces measures that are correct under every filter context and fast in VertiPaq, and gives a procedure for diagnosing the ones that are not.
Operating procedure
Step 1: Gather inputs
- The model schema: fact and dimension tables, relationships and their directions, and row counts on the facts.
- Whether a dedicated Date table exists, is marked as a date table, and covers a contiguous range - time intelligence silently misbehaves without all three.
- The business definition of each measure in one sentence, including what it should do under totals and slicers ("margin % weighted by revenue, respecting the category slicer").
- Performance symptoms if any: which visual, which page, how slow. Default target: any single visual renders in under 1 second; anything over 3 seconds is a defect to diagnose, not a fact of life.
Step 2: Choose measure vs calculated column
Prefer measures. They evaluate in the report's filter context and do not bloat the model. Use calculated columns only when you need a row-level value for slicing or relationships. Every calculated column is materialized and compressed into the model; every aggregation belongs in a measure.
Step 3: Write the measure with context in mind
Two contexts exist: filter context (slicers, rows, columns, CALCULATE) and row context (calculated columns, iterators like SUMX). CALCULATE is the only function that turns row context into filter context via context transition. A measure referenced inside SUMX is wrapped in an implicit CALCULATE - that context transition per row is both a correctness feature and a performance trap.
Base measure:
Total Sales = SUM ( Sales[Amount] )
Use variables for clarity and speed - evaluated once and reused:
Margin % =
VAR Revenue = [Total Sales]
VAR Cost = SUM ( Sales[Cost] )
RETURN DIVIDE ( Revenue - Cost, Revenue )
Always use DIVIDE instead of / to avoid divide-by-zero errors.
Step 4: Time intelligence on a marked date table
Sales YTD =
CALCULATE ( [Total Sales], DATESYTD ( 'Date'[Date] ) )
Sales PY =
CALCULATE ( [Total Sales], SAMEPERIODLASTYEAR ( 'Date'[Date] ) )
Sales YoY % =
DIVIDE ( [Total Sales] - [Sales PY], [Sales PY] )
If a time-intelligence measure returns blanks or wrong periods, check the three date-table conditions from Step 1 before touching the DAX - that is the cause in the large majority of cases.
Step 5: Control filter context deliberately
% of Total =
DIVIDE (
[Total Sales],
CALCULATE ( [Total Sales], ALLSELECTED ( Product[Category] ) )
)
ALLremoves all filters from a column or table.ALLSELECTEDrespects outer slicers but ignores inner row/column grouping.KEEPFILTERSintersects rather than overrides a filter inside CALCULATE.REMOVEFILTERSis the modern alias for clearing filters.
Pick by asking: should the denominator move when the user slices? ALLSELECTED if yes, ALL if never.
Step 6: Diagnose performance
Run Performance Analyzer, then copy the slow query into DAX Studio with server timings on. Read the split: the storage engine (VertiPaq scans) should dominate. When the formula engine consumes more than ~50% of query time, the measure is doing row-by-row work the storage engine cannot compress - rewrite it. Model-side levers, in order of payoff:
- Reduce cardinality of columns used in relationships; split datetime into separate date and time columns. A column with over ~1 million distinct values is a compression red flag.
- Prefer integer keys over strings.
- Avoid bidirectional relationships unless genuinely required; they multiply scan work and create ambiguity.
- Avoid iterators over large fact tables (10M+ rows) that reference measures per row; restate the logic as column arithmetic inside one SUMX, or pre-aggregate.
- Use
SELECTEDVALUEinstead ofHASONEVALUE+VALUESpatterns.
Worked artifact: bad/good measure pair
Business ask: sales for red products, respecting all other slicers.
Bad - iterates the entire fact table in the formula engine and forces a context transition per row:
Red Sales (Bad) =
CALCULATE (
[Total Sales],
FILTER ( Sales, RELATED ( Product[Color] ) = "Red" )
)
Good - a column predicate VertiPaq resolves as a compressed scan:
Red Sales (Good) =
CALCULATE ( [Total Sales], KEEPFILTERS ( Product[Color] = "Red" ) )
On a 50M-row fact table the bad version commonly runs seconds in the formula engine; the good version runs tens of milliseconds in the storage engine. Same numbers, two orders of magnitude apart. (KEEPFILTERS preserves an existing user filter on Color; drop it only if the measure must override the slicer.)
Second pair - weighted math. Bad: a calculated column Sales[Margin %] per row, then averaged in the visual - wrong weighting (simple average of row percentages) and model bloat. Good:
Weighted Margin =
SUMX ( Sales, Sales[Qty] * ( Sales[Price] - Sales[Cost] ) )
Row-by-row math belongs in an iterator inside a measure, using column arithmetic rather than nested measure references.
Deliverable
Produce a measure set where each measure has: the DAX, a one-sentence business definition, the expected behavior under totals and slicers, and - for any measure flagged slow - the DAX Studio storage/formula engine split before and after the rewrite.
Do NOT
- Do not use calculated columns for aggregations that belong in measures; the model pays in size and refresh time forever.
- Do not filter whole tables inside CALCULATE when a column predicate works;
FILTER ( Sales, ... )forces formula-engine iteration. - Do not average percentage columns in visuals; compute ratios as measures so weighting is correct at every level.
- Do not build time intelligence without a marked, contiguous Date table; the failure is silent wrong numbers, not an error.
- Do not reference measures inside iterators over large tables without checking the timing split; implicit context transition per row is the classic hidden cost.
Quality bar
- Every measure verified at the total level and under at least two slicer combinations, not just the detail rows.
- No division uses
/; all use DIVIDE. - Date table is marked, contiguous, and every time-intelligence measure filters through it.
- No visual over 1 second without a documented diagnosis; formula engine share under ~50% on the measures that matter.
- Model has no unexplained bidirectional relationships and no string keys on large relationships.
04 同仓库更多 Skills
有氧运动计划
zone-2-cardio-plan
当有人要求制定稳态有氧训练计划、进行有氧基础训练或达到第二区间、安排轻松或耐力型的每周有氧训练、按心率区间训练,或提高静息心率、最大摄氧量或耐力时,可以使用此方案。该方案构建了一个包含训练计划结构、训练方式选择和进度安排的心率区间有氧训练模块。本方案仅提供一般健身指导,不构成医疗建议。请勿用于设计力量或举重训练计划(请使用力量训练计划)、高强度间歇训练 (HIIT) 或循环训练(请使用体能训练和 HIIT 计划),或灵活性/柔韧性训练(请使用灵活性训练计划)。
youtube-script-writer
Writes retention-engineered long-form YouTube scripts on a hook/body/payoff architecture - a first-30-seconds hook that survives the retention cliff, a beat-sheet body with mini-hooks and bridges, timed pattern interrupts, and a payoff that over-delivers - with B-roll and editing cues marked inline. Use when someone says "script my next video", "my retention graph dies at the start", "tighten this draft", or "outline a video on X". Do NOT use for the 3-second opener of TikTok, Reels, or Shorts - use video-hook-writer instead; do NOT use for spoken voiceover synced to on-screen tutorial actions - use narration-script instead; do NOT use for a sales demo built on a buyer's discovery notes - use demo-script instead; do NOT use to design the thumbnail and title - use thumbnail-concept instead.
win-back-campaign
Designs segmented win-back email sequences for dormant users - dormancy tiers, a three-beat sequence with a single proportional incentive, and a suppression rule - and measures success by re-activation, not opens. Use when someone says "our users went quiet", "design a win-back campaign", "how do I re-engage lapsed customers", "should we email people who haven't logged in for months", or lifecycle messaging has stopped landing with a lapsed segment. Do NOT use for recovering an unfinished checkout - use abandoned-cart-sequence instead. Do NOT use for diagnosing and fixing why active customers cancel - use churn-reduction instead. Do NOT use for building always-on onboarding or nurture flows - use email-drip-builder instead.
wikipedia-style
Writes neutral, verifiable, encyclopedic prose following Wikipedia's core content policies and manual of style - NPOV, inline citations, notability-backed claims, and a strict ban on promotional language. Use when someone asks "write this like a Wikipedia article", "draft a Wikipedia page for this company or person", "make this neutral and encyclopedic", or "why does my article draft keep getting rejected". Do NOT use for persuasive or opinion writing - use op-ed-writer instead; for thesis-driven academic papers, use academic-essay; for verifying claims in existing text, use fact-checker.
whitepapers
Structures and writes authoritative B2B whitepapers - a standalone executive summary, a data-sized problem statement, methodology, evidence-driven findings, recommendations, and a soft call to action - flagging every claim that needs a real citation. Use when a marketer asks "write a whitepaper on this topic", "turn our research into a lead-gen asset", "make this credible enough for executives", or a draft reads like a product pitch instead of analysis. Do NOT use for customer-story-driven proof - use case-study-builder instead; for policy audiences, use policy-brief.
white-space-analysis
Finds unmet market gaps by ranking jobs-to-be-done on importance versus satisfaction, overlaying them against current solutions and workarounds, and validating that each gap is real, winnable, and worth winning. Use when someone asks "where are the gaps in this market", "what's underserved here", "where should we play next", or is hunting for product, feature, or market-entry opportunities. Do NOT use for profiling competitors and building battle cards - use competitive-intelligence instead; for putting a dollar figure on an identified opportunity - use market-sizing instead; for extracting jobs-to-be-done from raw customer interviews - use jtbd-extractor instead.