当前位置: 首页 > news >正文

Power BI中SUMMARIZE函数实战:DAX分组聚合原理与性能优化

1. 为什么我坚持用 SUMMARIZE() 而不是直接拖字段做矩阵——一个老Power BI开发者的实操坦白你有没有过这种经历在Power BI里拖出一个矩阵视觉对象把“年份”拉进行“产品”拉进列“销售额”放值区点几下就出报表了——看起来很美。但客户突然问“能不能只看2022年之后、华东大区、且单笔订单超5万的Top 10产品再按月度滚动平均算”你手一抖发现矩阵根本没法嵌套这么细的条件或者更糟你改完筛选器整个报表刷新慢得像在煮咖啡同事已经去茶水间转了三圈回来。这就是我十年前第一次被SUMMARIZE()救下的真实场景。它不是什么炫技函数而是DAX里最接近“SQL GROUP BY SELECT”的底层能力——你不是在界面上点选而是在数据模型内部亲手锻造一张有血有肉的新表。这张表一旦生成就能被任何视觉对象、任何度量值、甚至其他SUMMARIZE()二次加工完全脱离原始大宽表的性能枷锁。它解决的从来不是“怎么展示”而是“怎么让数据真正听你的话”。关键词全在这里SUMMARIZE()、Power BI、DAX、数据分组、聚合计算、SUMMARIZECOLUMNS()、GROUPBY()、ROLLUP()、ADDCOLUMNS()。这不是教科书里的语法罗列而是我在给银行做风控报表、给快消公司搭销售驾驶舱、给制造企业建设备OEE看板时每天都在调的“数据手术刀”。它不挑工具——你在Power BI Desktop里写在Excel Power Pivot的数据模型里写在SSAS Tabular的计算表里写逻辑完全一致。唯一区别是Power BI里它能实时联动切片器Excel里它得手动刷新而SSAS里它可能决定整个 cube 的查询响应时间。所以今天这篇我不讲“什么是DAX”不堆概念图只拆解你明天上班就要用的、带温度的实操细节什么时候该用它什么时候不该碰它参数填错一个字母会卡死还是静默出错以及——为什么我宁愿多写三行代码也坚决不用SUMMARIZE()去替代一个简单的度量值。2. SUMMARIZE() 的底层逻辑与设计哲学它到底在内存里干了什么2.1 它不是“计算”而是“造表”——理解DAX引擎的执行本质很多新手以为SUMMARIZE()是个“计算函数”就像SUM()或AVERAGE()那样输入一列数字输出一个数字。这是最大的认知陷阱。SUMMARIZE()的本质是表构造器Table Constructor。它在DAX引擎的内存中从源表出发执行三个原子动作扫描Scan逐行读取源表比如sales表但只读取你明确指定的groupBy_columnName列如sales[Year], sales[Region]和后续expression中引用的列如sales[SalesAmount]。其他列哪怕源表有100列它也完全无视——这本身就是第一层性能优化。分组Group对扫描到的指定列组合进行哈希分组Hash Grouping。例如当指定sales[Year]和sales[Region]时引擎会为每一对唯一的(2022, 华东)、(2022, 华南)、(2023, 华东)… 创建一个独立的“桶”Bucket。这个过程不依赖物理索引纯内存哈希所以速度极快但要求分组列不能有大量重复值后文详述。聚合Aggregate对每个“桶”里的所有行执行你定义的expression如SUM(sales[SalesAmount])。注意这个表达式是在每个分组上下文中独立计算的它自动继承该组的所有筛选上下文比如你加了日期切片器SUMMARIZE()生成的表也会自动过滤。提示你可以把SUMMARIZE()想象成一个微型ETL流程。它不修改源表也不创建物理存储而是在内存中瞬间完成“抽取指定列→转换分组→加载新表”三步。这张新表是惰性求值的——只有当你把它用在视觉对象里、或作为其他DAX函数的输入时引擎才真正执行这三步。这也是为什么你写完公式编辑器里不报错但放到报表里却卡住问题出在运行时而非定义时。2.2 语法结构的每一个字符都对应着一次内存操作官方语法是SUMMARIZE(table, groupBy_columnName[, groupBy_columnName]…[, name, expression]…)我们逐字拆解其背后的操作成本table必须是已存在的、命名的表名如sales不能是表达式如FILTER(sales, sales[Amount]1000)。因为引擎需要先定位这张表的内存地址才能开始扫描。如果你硬要传表达式DAX会强制先计算该表达式生成临时表再对临时表扫描——多了一次全表遍历性能雪崩。我见过有人写SUMMARIZE(FILTER(orders, orders[Status]Shipped), ...)结果10万行订单表报表刷新从2秒变成47秒。groupBy_columnName可以是多个顺序无关紧要但数量直接影响分组复杂度。分组组合数 各列唯一值数量的乘积。比如Region有5个值ProductCategory有20个Year有3个理论最大分组数就是5×20×3300。但如果Region和ProductCategory存在强相关比如“西北”区域只卖“建材”类实际分组数远小于此引擎会智能跳过空组合。但如果你加了个高基数列如OrderID10万唯一值哪怕只加一个分组数直接冲到10万内存爆满。name, expression这是聚合层。name只是新列的显示名无计算成本但expression是真正的性能杀手。它必须是一个标量表达式返回单个值且必须能被DAX引擎在分组上下文中求值。常见错误是这里写了COUNTROWS(sales)——它想统计每个分组的行数但COUNTROWS(sales)会忽略分组上下文返回整张sales表的总行数。正确写法是COUNTROWS(CURRENTGROUP())CURRENTGROUP()是SUMMARIZE()的隐式函数代表当前分组内的所有行。另一个坑是expression里引用了未在groupBy_columnName中出现的列比如分组只用了Year但表达式写了AVERAGE(sales[DiscountRate])——引擎会报错因为它无法确定DiscountRate在每个Year组内该如何聚合是取平均最大值还是报错。2.3 它和传统SQL GROUP BY的根本差异没有HAVING但有更狠的替代方案SQL里GROUP BY后面跟HAVING来过滤分组结果如HAVING SUM(Amount) 10000。SUMMARIZE()没有HAVING子句。但这不意味着它做不到。它的解决方案更底层、更灵活方案一用FILTER包裹SUMMARIZE()FILTER(SUMMARIZE(...), [Total Sales] 10000)这是最直观的。但注意FILTER是先生成完整汇总表再逐行过滤。如果分组数巨大比如100万组FILTER就得遍历100万行效率低。方案二用SUMMARIZECOLUMNS()替代推荐SUMMARIZECOLUMNS(Region, Total, SUM(Sales[Amount]), FilterFlag, FILTER(Sales, Sales[Amount]10000))不对语法错了。正确是SUMMARIZECOLUMNS(Region, Total Sales, SUM(Sales[Amount]), IsBig, IIF(SUM(Sales[Amount])10000, 1, 0))然后在外面套FILTER。但更优解是——直接把过滤条件写在SUMMARIZECOLUMNS的filter参数里SUMMARIZECOLUMNS(Region, FILTER(Sales, Sales[Amount]10000), Total Sales, SUM(Sales[Amount]))。看到区别了吗FILTER在SUMMARIZECOLUMNS内部执行它先从Sales表里筛出Amount10000的行假设1万行再对这1万行做分组。比先分组100万组再过滤快一个数量级。方案三用CALCULATEALL组合高级在度量值里用CALCULATE(SUM(Sales[Amount]), ALL(Sales), Sales[Year]MAX(Sales[Year]))模拟分组过滤。但这属于另一套范式不在本文展开。实操心得我给自己定了一条铁律——只要分组后需要按聚合结果过滤优先用SUMMARIZECOLUMNS()而不是SUMMARIZE()FILTER()。前者是“先筛后聚”后者是“先聚后筛”在大数据量下前者能省掉90%的内存和CPU。这条规则在我给某电商平台做“爆款商品周榜”时救了命原始SUMMARIZE()生成200万组加FILTER后报表卡死换成SUMMARIZECOLUMNS()加FILTER3秒出结果。3. 从零开始的四层实战基础分组、多维钻取、层级汇总、动态扩展3.1 基础分组别只盯着“年份”试试“财年季度”的组合拳假设你拿到的销售数据表sales有OrderDate订单日期、ProductID、Amount三列。老板第一句话“给我看2023财年各季度销售额”。注意是“财年”不是自然年。很多新人直接写QtrSummary SUMMARIZE( sales, FiscalYear, YEAR(sales[OrderDate]) IF(MONTH(sales[OrderDate])7, 1, 0), FiscalQuarter, Q CEILING(MONTH(sales[OrderDate])/3, 1), TotalAmount, SUM(sales[Amount]) )这看起来没问题但致命错误YEAR()和MONTH()是标量函数它们在SUMMARIZE()的groupBy_columnName位置是非法的SUMMARIZE()的分组列必须是物理列名或已存在的计算列名不能是即时计算的表达式。正确做法分两步第一步在sales表里新增两个计算列非度量值FiscalYear YEAR(sales[OrderDate]) IF(MONTH(sales[OrderDate])7, 1, 0)FiscalQuarter Q CEILING(MONTH(sales[OrderDate])/3, 1)第二步用这两个新列做分组QtrSummary SUMMARIZE( sales, sales[FiscalYear], sales[FiscalQuarter], TotalAmount, SUM(sales[Amount]) )为什么必须这样因为SUMMARIZE()的分组动作发生在引擎扫描阶段它需要一个稳定的、可哈希的列值。如果允许在分组时动态计算每次扫描都要重新算一遍YEAR()性能灾难。而计算列是在数据刷新时一次性算好存入内存分组时直接取值快如闪电。注意事项计算列会占用内存。如果sales表有1亿行FiscalYear列就是1亿个整数。但比起SUMMARIZE()运行时动态计算1亿次YEAR()内存换时间永远划算。我通常会把所有用于分组的业务逻辑财年、工作日、客户等级、产品生命周期阶段都提前做成计算列模型一加载分组就丝滑。3.2 多维钻取用“地区-城市-门店”三级分组看清增长引擎在哪现在需求升级“我要看华东大区下各城市、各门店的销售额和毛利率”。数据表sales里有Region、City、StoreID、Amount、Cost列。直接写StoreSummary SUMMARIZE( sales, sales[Region], sales[City], sales[StoreID], Sales, SUM(sales[Amount]), GrossMargin, DIVIDE(SUM(sales[Amount]) - SUM(sales[Cost]), SUM(sales[Amount]), 0) )这能跑通但有个隐藏雷区空值Blank处理。如果某个StoreID的Amount全是空SUM(sales[Amount])返回BLANKDIVIDE(..., BLANK(), 0)会返回0但这个0是错的——它本应是空表示无数据。更糟的是如果Region或City列有空值SUMMARIZE()会把所有空值归为一个组叫blank报表里突然冒出一个“未知地区-未知城市-未知门店”客户会懵。我的标准解法是在SUMMARIZE()前用FILTER预清洗。StoreSummary SUMMARIZE( FILTER( sales, NOT(ISBLANK(sales[Region])) NOT(ISBLANK(sales[City])) NOT(ISBLANK(sales[StoreID])) sales[Amount] 0 ), sales[Region], sales[City], sales[StoreID], Sales, SUM(sales[Amount]), GrossMargin, VAR TotalSales SUM(sales[Amount]) VAR TotalCost SUM(sales[Cost]) RETURN IF(TotalSales 0, DIVIDE(TotalSales - TotalCost, TotalSales, 0), BLANK()) )这里用了VAR定义中间变量让逻辑清晰用IF确保分母不为零最关键的是FILTER它把脏数据在分组前就剔除SUMMARIZE()只处理干净数据结果表里绝不会出现blank组。这个习惯让我在给某连锁药店做全国门店分析时避免了37家“总部直营店”被误归为“未知城市”的尴尬。3.3 层级汇总ROLLUP()不是加小计而是构建决策树客户说“我要看华东、华南、华北三大区的总销售额同时也要看到每个区内各城市的明细最后还要一个全国总计。”这就是典型的层级汇总Hierarchical Summary。很多人第一反应是建三个SUMMARIZE()表再用UNION合并。太重了。ROLLUP()就是为此生的。但它不是简单加一行“小计”而是在分组键上构建一个维度金字塔。RegionalSummary SUMMARIZE( sales, ROLLUP(sales[Region], sales[City]), Sales, SUM(sales[Amount]) )这段代码生成的表行结构是这样的RegionCitySales华东上海120000华东南京95000华东杭州88000华东(Blank)303000华南广州110000华南深圳105000华南(Blank)215000(Blank)(Blank)518000看到没(Blank)不是错误是ROLLUP()的标记符代表“此层级汇总”。引擎自动识别Region和City的层级关系生成三级结果明细RegionCity、一级小计RegionBlank、二级总计BlankBlank。但ROLUP()有个坑它不支持自定义小计名称。你不能说“把华东小计叫‘华东合计’全国总计叫‘集团总览’”。它永远用(Blank)。所以我的做法是用ISINSCOPE()函数在视觉对象里做条件格式。在矩阵视觉对象里把Region和City拖进去值放[Sales]然后在“格式”面板里找到“小计”关掉默认小计再新建一个度量值SalesDisplay SWITCH( TRUE(), ISINSCOPE(sales[City]) ISINSCOPE(sales[Region]), FORMAT([Sales], #,##0), ISINSCOPE(sales[Region]) NOT(ISINSCOPE(sales[City])), 【 SELECTEDVALUE(sales[Region]) 小计】 FORMAT([Sales], #,##0), NOT(ISINSCOPE(sales[Region])) NOT(ISINSCOPE(sales[City])), 【集团总览】 FORMAT([Sales], #,##0), FORMAT([Sales], #,##0) )这样报表里显示的就是带中文标签的清晰层级而不是一堆(Blank)。这才是给老板看的报表。3.4 动态扩展ADDCOLUMNS()不是锦上添花而是让汇总表活起来SUMMARIZE()生成的表是静态的只有你定义的那几列。但业务需求是活的。比如你刚做了StoreSummary表包含Region、City、StoreID、Sales。老板马上问“这些门店里哪些是新开的开业6个月哪些是高潜力销售额环比涨超30%”你不可能回去改SUMMARIZE()公式因为Sales是聚合值没有原始日期信息。ADDCOLUMNS()就是答案。它像给一张照片加滤镜——不改变原图但叠加新信息。StoreSummaryExtended ADDCOLUMNS( SUMMARIZE( sales, sales[Region], sales[City], sales[StoreID], Sales, SUM(sales[Amount]) ), IsNewStore, VAR StoreFirstDate CALCULATE(MIN(sales[OrderDate]), ALLEXCEPT(sales, sales[StoreID])) RETURN IF(TODAY() - StoreFirstDate 180, 是, 否), GrowthRate, VAR CurrentSales [Sales] VAR LastPeriodSales CALCULATE( SUM(sales[Amount]), DATEADD(sales[OrderDate], -1, MONTH), ALLEXCEPT(sales, sales[StoreID]) ) RETURN IF(LastPeriodSales 0, DIVIDE(CurrentSales - LastPeriodSales, LastPeriodSales, 0), BLANK()), PotentialLevel, SWITCH( TRUE(), [GrowthRate] 0.3, 高潜力, [GrowthRate] 0.1, 中潜力, [GrowthRate] 0, 稳定, 待观察 ) )关键点解析ALLEXCEPT(sales, sales[StoreID])这是核心。它告诉引擎“在计算每个门店的首单日期时只保留StoreID的筛选其他所有筛选如时间切片器都清除”。否则MIN(sales[OrderDate])会被当前报表的日期范围限制算不出真正的开业日。DATEADD(sales[OrderDate], -1, MONTH)这是DAX的时间智能函数自动处理月末、闰年等边界。比手动写sales[OrderDate] - 30靠谱一万倍。SWITCH(TRUE(), ...)比嵌套IF更易读也更高效。这张扩展后的表可以直接拖进表格视觉对象IsNewStore列能做切片器PotentialLevel能设条件格式变色。它让一张静态汇总表变成了一个动态的、可交互的决策仪表盘。4. 避坑指南那些让我加班到凌晨三点的SUMMARIZE()陷阱实录4.1 性能雪崩的三大元凶与我的急救包元凶一高基数分组列High-Cardinality Column现象报表刷新时间从5秒飙升到3分钟任务管理器里powerbi.exe内存占用飙到8GB。诊断打开DAX Studio运行SUMMARIZE(sales, sales[CustomerID])看返回多少行。如果CustomerID有50万唯一值SUMMARIZE()就要建50万个“桶”内存爆炸。我的急救包立即停用把CustomerID从分组列移除改用CustomerSegment如VIP/普通/流失这类低基数列。终极方案用SUMMARIZECOLUMNS()TOPN()。例如只取销售额Top 100的客户Top100Customers SUMMARIZECOLUMNS( TOPN(100, VALUES(sales[CustomerID]), SUM(sales[Amount]), DESC), Sales, SUM(sales[Amount]) )元凶二在表达式里滥用RELATED()现象SUMMARIZE()公式不报错但放在矩阵里某个单元格显示#VALUE!且整个视觉对象变灰。原因RELATED()函数只能在“一对多”关系的“一”侧表里使用。如果你在sales表多侧的SUMMARIZE()里写RELATED(customers[CustomerName])而sales和customers的关系是sales[CustomerID] - customers[CustomerID]标准一对多那么RELATED()会失败因为sales是多侧。我的急救包查关系方向在模型视图里看关系线箭头指向哪边。箭头指向的表是“一”侧可以被RELATED()引用。正确姿势在customers表一里建SUMMARIZE()或用LOOKUPVALUE()更安全但稍慢LOOKUPVALUE(customers[CustomerName], customers[CustomerID], sales[CustomerID])元凶三循环依赖Circular Dependency现象编辑器里红色波浪线提示“检测到循环依赖”公式无法保存。典型场景你在一个叫SummaryTable的SUMMARIZE()表里expression引用了另一个叫SalesMeasure的度量值而这个SalesMeasure又引用了SummaryTable比如用COUNTROWS(SummaryTable)做分母。我的急救包断链把SalesMeasure里的COUNTROWS(SummaryTable)替换成DISTINCTCOUNT(sales[CustomerID])假设你要数客户数。原则SUMMARIZE()表是物理表度量值是逻辑计算。永远不要让逻辑计算依赖物理表除非你明确知道后果。我的规则是SUMMARIZE()表只被视觉对象和CALCULATE()引用绝不被其他度量值直接引用。4.2 结果诡异的四大幻觉与我的排查清单幻觉一“数据对不上”——SUMMARIZE() vs 矩阵视觉对象数值差10%排查清单检查SUMMARIZE()的源表是否和矩阵用的同一个表有没有不小心用了sales_raw和sales_clean两个不同版本检查SUMMARIZE()里expression是否用了SUMX()而矩阵用的是SUM()SUMX()是逐行计算再求和SUM()是直接求和如果Amount列有公式结果可能不同。最关键检查筛选上下文。把SUMMARIZE()表单独建一个表视觉对象不加任何切片器看数值。再把矩阵视觉对象也清空所有切片器。如果两者还不同那就是公式问题如果相同说明是切片器影响了其中一个。幻觉二“为什么有这么多 ”——空值组泛滥排查清单用COUNTBLANK()检查分组列COUNTBLANK(sales[Region])。如果0说明源数据就有空。在SUMMARIZE()前加FILTER(..., NOT(ISBLANK()))如前所述。检查关系如果分组列来自关联表如sales[Region]其实是regions[RegionName]确认关系是否激活且regions表里没有空行。幻觉三“排序乱了”——分组列顺序和报表显示顺序不一致原因SUMMARIZE()本身不保证输出顺序。DAX引擎按内存哈希顺序输出不是按字母或数字顺序。我的解法在视觉对象里排序选中矩阵的行字段如Region右键→“按列排序”选择一个数值列如RegionSortOrder来定义顺序。在SUMMARIZE()里加排序列新增一列SortKey, SWITCH(sales[Region], 华东, 1, 华南, 2, 华北, 3, 4)然后在视觉对象里按此列排序。幻觉四“明明有数据却显示空白”——表达式返回BLANK的隐形杀手常见原因DIVIDE(x, y, 0)的第三参数是0但y是BLANKDIVIDE(BLANK(), BLANK(), 0)返回0不是你想要的空。SUM()遇到全BLANK列返回BLANK但COUNTROWS()遇到空组返回0。我的统一解法SafeSum VAR Result SUM(sales[Amount]) RETURN IF(ISBLANK(Result), BLANK(), Result)所有聚合表达式都套一层SafeSum确保逻辑一致。4.3 替代方案选型决策树SUMMARIZE()、SUMMARIZECOLUMNS()、GROUPBY()何时用谁面对一个新需求我脑中立刻弹出这个决策树| 问题 | 是 | 否 | 下一步 | |------|----|----|--------| | **是否需要在汇总表里直接应用筛选器如日期范围、产品类别** | → 选 **SUMMARIZECOLUMNS()** | → 进入下一问 | | | **是否只在一个表内分组且分组逻辑极其简单如按单列求和** | → 选 **GROUPBY()** | → 进入下一问 | | | **是否需要跨表关联如sales表分组但聚合时要取products表的分类名** | → 必须用 **SUMMARIZE()** | → 可用 **SUMMARIZECOLUMNS()** 或 **SUMMARIZE()** | | | **是否需要在汇总表里添加复杂的、依赖多表的计算列如客户生命周期价值CLV** | → 用 **SUMMARIZE() ADDCOLUMNS()** | → 用 **SUMMARIZECOLUMNS()** | |真实案例对比场景A给财务部做“各费用科目月度支出汇总”数据源只有expenses一张表需按Month和AccountCode分组且要加一个切片器控制Year。→ 直接SUMMARIZECOLUMNS(expenses[Month], expenses[AccountCode], FILTER(expenses, expenses[Year]SELECTEDVALUE(Years[Year])), Amount, SUM(expenses[Amount]))。快、稳、准。场景B给市场部做“各渠道获客成本CAC”需leads表线索和costs表广告花费关联按Channel分组计算SUM(costs[Spent]) / COUNTROWS(leads)。→ 必须SUMMARIZE(leads, leads[Channel], CAC, DIVIDE(SUM(costs[Spent]), COUNTROWS(leads)))。因为要跨表SUMMARIZECOLUMNS()不支持直接跨表关联它要求所有列来自同一表或通过关系可访问但聚合逻辑复杂时SUMMARIZE()更可控。场景C给IT部做“服务器CPU使用率TOP 10”数据在server_metrics表只需按ServerName分组求AVERAGE(CPUUsage)。→GROUPBY(server_metrics, server_metrics[ServerName], AvgCPU, AVERAGEX(CURRENTGROUP(), server_metrics[CPUUsage]))。GROUPBY()在此场景比SUMMARIZE()快15%因为它的CURRENTGROUP()机制更轻量。5. 高阶武器库ROLLUPGROUP()、SUMMARIZECOLUMNS()深度实战与我的私藏模板5.1 ROLLUPGROUP()当ROLLUP()不够用时你需要的精准控制权ROLLUP()是粗放的“全层级汇总”但业务常需要“选择性汇总”。比如老板说“给我看华东、华南、华北的销售额但华北只看北京、上海、广州三个重点城市其他城市合并为‘华北其他’。” ROLLUP()做不到它要么全汇总要么全明细。ROLLUPGROUP()就是为此而生。它让你在同一个SUMMARIZE()里对不同列组合定义不同的汇总粒度。CustomRollup SUMMARIZE( sales, sales[Region], ROLLUPGROUP( sales[City], sales[StoreID] ), Sales, SUM(sales[Amount]) )这段代码的效果是当Region是“华东”它会展开所有City和StoreID明细。当Region是“华北”它会把所有City和StoreID合并为一个组即blank相当于“华北其他”。但ROLLUPGROUP()更强大的是嵌套。比如你想对“华东”做城市级汇总对“华北”做省级汇总即只到Region不展CityAdvancedRollup SUMMARIZE( sales, sales[Region], ROLLUPGROUP( sales[City], ROLLUPGROUP( sales[StoreID] ) ), Sales, SUM(sales[Amount]) )这时ROLLUPGROUP(sales[StoreID])会让StoreID层总是汇总即不展开门店而外层ROLLUPGROUP(sales[City], ...)则控制城市层的行为。通过这种嵌套你能构建出任意复杂的、符合业务语义的汇总结构。实操心得ROLLUPGROUP()的语法极易出错。我建议永远用括号明确包裹不要省略。比如ROLLUPGROUP(sales[City], sales[StoreID])是对的但ROLLUPGROUP(sales[City], sales[StoreID], Label)是错的——ROLLUPGROUP()只接受列名不接受字符串。这个错误我踩过三次每次都要重启Power BI。5.2 SUMMARIZECOLUMNS()从入门到精通的五个必记模式SUMMARIZECOLUMNS()是SUMMARIZE()的进化版专为高性能、复杂筛选设计。它的语法是SUMMARIZECOLUMNS(groupBy_columnName[, groupBy_columnName]…[, filterTable]…[, name, expression]…)模式一基础筛选Filter TableFilteredSummary SUMMARIZECOLUMNS( sales[Region], sales[ProductCategory], FILTER(sales, sales[Amount] 1000 sales[OrderDate] DATE(2023,1,1)), TotalSales, SUM(sales[Amount]) )FILTER()是第一个参数它先于分组执行大幅减少扫描行数。模式二多表筛选Multiple Filter TablesMultiFilterSummary SUMMARIZECOLUMNS( sales[Region], FILTER(sales, sales[Amount] 1000), FILTER(products, products[IsPremium] TRUE()), PremiumSales, SUM(sales[Amount]) )可以同时加多个FILTER引擎会做交集AND。模式三度量值直出Measures in OutputMeasureSummary SUMMARIZECOLUMNS( sales[Region], TotalSales, [Total Sales Measure], // 直接引用度量值 AvgOrderValue, [Avg Order Value Measure] )无需ADDCOLUMNS()度量值可直接作为输出列且自动继承筛选上下文。模式四空值处理Blank HandlingSUMMARIZECOLUMNS()默认会过滤掉所有聚合结果为BLANK的行。如果你想保留加KEEPFILTERS()KeepBlankSummary SUMMARIZECOLUMNS( KEEPFILTERS(sales[Region]), Sales, SUM(sales[Amount]) )模式五动态列名Dynamic Column Names用SELECTEDVALUE()和CONCATENATEX()生成列名DynamicSummary SUMMARIZECOLUMNS( sales[Region], Sales_ SELECTEDVALUE(Years[Year]), SUM(sales[Amount]) )虽然不常用但在做参数化报表时很酷。5.3 我的私藏模板一个能应对90%场景的SUMMARIZE()通用框架经过上百个项目锤炼我总结出这个万能模板。你只需替换方括号里的内容就能生成一个健壮、可维护、高性能的汇总表
http://www.rkmt.cn/news/1390546.html

相关文章:

  • 不止于制图:用ArcGIS渔网工具Create Fishnet做空间采样与数据分析的实战思路
  • WeChatExporter:3步永久保存微信聊天记录的完整指南
  • 终极风扇控制指南:用FanControl彻底解决电脑噪音与散热问题
  • 结构方程模型(SEM):理论驱动的潜变量因果建模全解析
  • YOLACT实例分割从入门到部署:手把手教你训练自定义数据集
  • 从LoRA微调到文本化继承:AI价值观塑造的第三条道路探索
  • 别再凭感觉选二极管了!手把手教你用Excel搞定功率二极管损耗计算(附模板)
  • 手把手教你搞定VSCode主题Monokai Pro的许可证弹窗(附两种实测方法)
  • R绘图实战|GSEA富集分析结果解读与高级可视化
  • CentOS 7/8 普通用户突然用不了sudo?别慌,3分钟教你搞定 ‘user not in sudoers‘ 错误
  • 告别加班!用这个Allegro插件5分钟搞定DDR多负载等长约束(附Auto_Create_Match_Group.il文件)
  • 告别ArcEngine 9.x:在VS2019中配置10.8开发环境的完整指南与项目迁移心得
  • 英雄联盟自动化工具:告别手忙脚乱,用智能工具提升你的游戏体验
  • Switch玩家必看:PotPlayer无边框录制终极指南,让你的游戏视频像直播一样干净
  • Windows变身AirPlay接收器:三步解锁iPhone投屏新体验
  • 实战指南:利用Python与WinAppDriver构建Windows桌面应用UI自动化测试框架
  • 为ubuntu上的claude code配置taotoken作为稳定后备api源
  • UEFI还是BIOS?手把手教你根据启动模式选择正确的Deepin卸载工具
  • Awoo Installer:Switch游戏安装的终极指南
  • 网盘直链下载助手完整指南:如何轻松获取9大网盘真实下载链接
  • 手把手教你用Burp Suite和Stegsolve破解HarryNull Cipher前10关(附环境配置)
  • Unity资源加载性能优化:Profiler深度诊断与真机验证方法论
  • 用STM32CubeMX玩转PWM:手把手实现呼吸灯与舵机控制(基于TIM3)
  • 你的Linux内核配置藏哪儿了?手把手教你用/proc/config.gz和extract-ikconfig脚本找出来
  • 天机智能宣布融资10亿:估值近百亿 高瓴与美团联合领投
  • MyComputerManager:一键清理Windows顽固快捷方式的轻量级工具
  • 如何快速部署LocalVocal:打造专业级离线实时字幕系统的完整实践指南
  • Alteryx拖拽式ETL实战:零代码构建可交付数据清洗流水线
  • Windows桌面应用禁用关闭按钮的可靠拦截方案
  • 航模冗余供电系统设计:从线性稳压到双路备份的工程实践