关于 tmdl
tmdl 是为在 PBIP 项目中直接编写和编辑 TMDL 文件提供的指导技能,适用于缺少 Tabular Editor CLI、Power BI MCP 服务或 connect-pbid 时的文本级修改。它涵盖语法与对象结构,但直接编辑不会验证 DAX 或引用完整性。
主要功能
- 01指导编辑表、列、度量值和关系
- 02说明缩进、命名与属性顺序
- 03提供 DAX 与描述的 TMDL 写法
- 04梳理 TMDL 文件类型和对象嵌套
- 05提醒直接编辑的验证限制
适用场景
- 01在 Git 仓库中修改 PBIP 模型文件
- 02快速调整描述或格式字符串
- 03添加或修改 TMDL 度量值
- 04检查 TMDL 语法规则
MCP 相关
该技能建议优先使用 Power BI MCP 服务等工具;当它不可用时,可作为直接编辑 TMDL 文件的替代指导。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ data-goblin/ power-bi-agentic-development --skill tmdl安装后在 Claude Code 中输入/tmdl确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/SpaceParts.SemanticModel/definition/database.tmdlexpressions.tmdlfunctions.tmdlmodel.tmdlrelationships.tmdlexamples/SpaceParts.SemanticModel/definition/perspectives/Measure Selection.tmdlNo Measure Selection.tmdlexamples/SpaceParts.SemanticModel/definition/roles/Account Managers.tmdlBrand VPs.tmdlBusiness Line Leaders.tmdlKey Account Managers.tmdlStation Sales Managers.tmdlSystem Regional Managers.tmdlSystem Sales Directors.tmdlTerritory Managers.tmdlexamples/SpaceParts.SemanticModel/definition/tables/__Demo UDFs.tmdl__Measures.tmdl__SVGs.tmdl1) Selected Metric.tmdl2) Selected Unit.tmdl3) Selected Target.tmdl4) Selected Period.tmdlBrands.tmdlBudget Rate.tmdlBudget.tmdlCustomers.tmdlDate.tmdlEmployees.tmdlExchange Rate.tmdlForecast.tmdl详细介绍
TMDL 编写
直接在 PBIP 项目中编写和编辑 TMDL(表格模型定义语言)文件的专家指南。
此技能仅作为最后手段。 直接编辑 TMDL 文件缺少 Tabular Editor CLI、Power BI MCP 服务或
connect-pbid技能(通过 PowerShell 使用 TOM)提供的验证、原子性和 DAX 查询能力。条件允许时,请使用这些工具。适合编辑 TMDL 的情况:
- 在未打开 Power BI Desktop 的情况下,处理 Git 仓库中的 PBIP 文件
- 未安装 Tabular Editor CLI 或 MCP 服务
- 快速修复文本内容(描述、格式字符串、显示文件夹),无需动用完整工具链
直接编辑 TMDL 不会验证 DAX 语法、检查引用完整性,也不会验证属性值是否合法。只有在模型下次由 Power BI Desktop 加载或通过 XMLA 部署时,才会显现错误。在 Power BI Desktop 中打开之前,请使用
pbip-validatorAgent 检查 TMDL 文件中的语法问题、缩进错误和引用完整性。
何时使用此技能
仅当 Tabular Editor CLI、Power BI MCP 服务或 connect-pbid 技能不可用,且任务涉及以下内容时,才启用此技能:
- 直接编辑
.tmdl文件(度量值、列、表、关系) - 在 TMDL 中添加或修改度量值定义
- 为列、度量值或表添加描述
- 修复
summarizeBy或formatString值 - 了解 TMDL 语法规则(缩进、引号、属性顺序)
- 以 TMDL 格式编写多行 DAX
- 了解
///描述与//注释的区别
重要事项
///(三个斜杠)会为其紧随其后的对象设置Description属性。///行必须紧接声明(measure、column、table等),不能是空行或另一行///。普通注释请使用//。- 缩进具有语义。 TMDL 使用空白缩进表示层级,缩进深度对应嵌套层级(TMDL 规范 — 缩进)。PBIP 文件每层使用一个制表符,因为 Power BI Desktop 和 TOM
TmdlSerializer默认采用IndentationMode.Tabs。空格也有效(IndentationMode.Spaces,默认每层 4 个空格),但同一文件中必须保持一致;混用或错误缩进会破坏模型。表的属性缩进一层;列的属性(列属于表)缩进两层。 - 名称的引号规则: 仅当名称包含空格、特殊字符或以数字开头时,才需要加引号。简单名称和以下划线开头的名称不加引号。详情请参阅“名称引号”部分。
- M 表达式和表共用同一命名空间。
expressions.tmdl中由expression <name>声明的名称,与tables/*.tmdl中由table <name>声明的名称冲突时,Power BI Desktop 会在加载时失败并报错'duplicate member <name>'。请使用不同的名称;惯用的解决方法是在 M 表达式名称后添加Query或Source后缀,并让分区通过source = #"<Name> Query"引用该表达式。validate_pbip.py会将此问题作为错误进行检查。
TMDL 文件类型
| 文件 | 内容 | 位置 |
|---|---|---|
model.tmdl | 模型配置、ref table 条目、查询组、注释 | definition/ |
database.tmdl | 兼容性级别、模型 ID | definition/ |
relationships.tmdl | 表之间的所有关系 | definition/ |
expressions.tmdl | 共享 M 表达式和参数 | definition/ |
functions.tmdl | DAX 用户定义函数(可重用的参数化 DAX) | definition/ |
roles/<RoleName>.tmdl | 每个安全角色对应一个文件(RLS 筛选器、角色成员、OLS) | definition/roles/ |
perspectives/<Name>.tmdl | 每个透视对应一个文件(对象成员资格) | definition/perspectives/ |
dataSources.tmdl | 旧版数据源定义(若存在) | definition/ |
tables/<Name>.tmdl | 表定义,包含列、度量值、层次结构、分区 | definition/tables/ |
cultures/<locale>.tmdl | 语言元数据和翻译 | definition/cultures/ |
对象嵌套规则
对象必须嵌套在正确的父对象中。验证器会强制执行以下规则:
| 对象 | 允许的父对象 |
|---|---|
column、measure、hierarchy、partition、calculationGroup | table |
level | hierarchy |
calculationItem | calculationGroup |
tablePermission | role |
columnPermission | tablePermission |
perspectiveTable | perspective |
perspectiveColumn、perspectiveMeasure、perspectiveHierarchy | perspectiveTable |
linguisticMetadata、translation | cultureInfo |
dataAccessOptions | model |
formatStringDefinition | measure、calculationItem |
detailRowsDefinition | measure、table |
alternateOf | column |
member | role |
annotation、extendedProperty | 任意对象(包括 queryGroup、function、member) |
ref | model、table |
根级对象(仅限缩进 0):model、database、table、relationship、role、cultureInfo、perspective、dataSource、expression、queryGroup、function。
语法规则
缩进
TMDL 使用空白缩进,缩进深度等于嵌套层级。PBIP 文件每层使用一个制表符(TOM TmdlSerializer 的默认设置),因此以下所有示例都使用制表符:
table Product // depth 0: top-level declaration
lineageTag: abc-123 // depth 1: table property
measure '# Products' = // depth 1: measure declaration
COUNTROWS ( // depth 3: DAX expression body (one deeper than properties)
VALUES ( Product[Name] ) // depth 3: continued
) // depth 3: continued
formatString: #,##0 // depth 2: measure property
displayFolder: Measures // depth 2: measure property
lineageTag: def-456 // depth 2: measure property
column 'Product Name' // depth 1: column declaration
dataType: string // depth 2: column property
lineageTag: ghi-789 // depth 2: column property
summarizeBy: none // depth 2: column property
sourceColumn: Product Name // depth 2: column property
annotation SummarizationSetBy = Automatic // depth 2: column annotation
主要规则:
- PBIP 文件中使用制表符(Power BI Desktop 的默认设置);空格替代方案请参阅上文的“关键”部分
- 表级对象(列、度量值、层次结构、分区)的深度为 1
- 这些对象的属性深度为 2
- 多行 DAX 表达式主体的缩进深度始终比其所属声明深 2 层(表内度量值/列的深度为 3;顶级函数的深度为 2;calculationItem 的深度为 4)
- 注释的缩进深度与其父对象的属性相同,中间以空行分隔
描述(///)
三斜线会将 Description 属性设置到下一条声明。这是原生 TMDL 语法(不是 Tabular Editor 扩展);TMDL 规范将 /// 视为一等描述支持。
/// Count of distinct products in the current filter context.
measure '# Products' =
COUNTROWS ( VALUES ( Product[Product Name] ) )
formatString: #,##0
lineageTag: abc-123
规则:
///的下一行必须紧接一条声明///和声明之间不得有空行- 多个
///行会合并为一条描述 ///适用于下一条measure、column、table、hierarchy或level
常见错误:
// WRONG: blank line between /// and declaration
/// This is a description.
measure 'My Measure' = 1
// WRONG: /// used as a separator comment
///
measure 'My Measure' = 1
// RIGHT: /// immediately before declaration
/// This is a description.
measure 'My Measure' = 1
// RIGHT: // used for regular comments
// This is just a comment, not a description.
measure 'My Measure' = 1
注释(//)
双斜线是普通注释,不具备语义效果:
// This is a comment — it does not set any property
measure 'My Measure' = 1
属性顺序
虽然 TMDL 不严格要求属性顺序,但应保持一致。常用顺序如下:
列: dataType、isHidden、isKey、displayFolder、lineageTag、summarizeBy、isNameInferred、sourceColumn、sortByColumn,然后是注释。
度量值: DAX 表达式(位于 = 行或跨多行)、formatString 或 formatStringDefinition、displayFolder、lineageTag,然后是注释。
名称引号
何时使用引号
名称中含有以下任一字符时,请使用单引号括起来:
- 空格:
'Product Name' - 句点:
'Sales.Amount' - 等号:
'Price = Target' - 冒号:
'Date:Key' - 单引号(通过重复单引号进行转义):
'Customer''s Name' - 其他特殊字符:
'Sales ($)'、'OTD % (Value)'、'1) Selected Metric' - 以数字开头的名称:
'4) Selected Period'
何时不使用引号
简单标识符无需使用引号:
Product(简单单词)_Measures(下划线前缀,无空格)Date(简单单词)CgMetricQuantity(PascalCase,无空格)
示例
table Product // unquoted: simple name
table _Measures // unquoted: underscore prefix
table 'Budget Rate' // quoted: contains space
table 'Invoice Document Type' // quoted: contains spaces
table '1) Selected Metric' // quoted: starts with digit
table 'On-Time Delivery' // quoted: contains space
列定义
完整的列示例(基本、隐藏、键、sortByColumn、描述)请参阅 references/tmdl-file-examples.md。完整的属性参考请参阅 references/column-properties.md。
关键列模式:
column 'Product Name'
dataType: string
displayFolder: 1. Product Hierarchy
lineageTag: abc-123
summarizeBy: none
sourceColumn: Product Name
annotation SummarizationSetBy = Automatic
度量值定义
单行 DAX
measure '# Products' = COUNTROWS ( VALUES ( Product[Product Name] ) )
formatString: #,##0
displayFolder: Measures
lineageTag: abc-123
多行 DAX
多行 DAX 有两种语法:
1. 缩进代码块(最常见)——表达式正文的缩进比声明多两级:
2. 三反引号代码块——将 DAX 放在 ``` 围栏中,适用于缩进较复杂的表达式:
measure Percentage = ```
VAR _Total = CALCULATE( SUM ( 'Table'[Quantitative] ), REMOVEFILTERS ( ) )
RETURN
DIVIDE ( SUM ( 'Table'[Quantitative] ), _Total )
```
formatString: 0.0%;-0.0%;0.0%
lineageTag: abc-123
缩进代码块语法(标准方式)——比度量值的父级(表)多缩进两个制表符:
measure 'Actuals MTD' =
CALCULATE (
[Actuals],
CALCULATETABLE (
DATESMTD ( 'Date'[Date] ),
'Date'[IsDateInScope]
)
)
formatString: #,##0
displayFolder: 2. MTD\Actuals
lineageTag: abc-123
带描述的度量值
/// Number of workdays elapsed month-to-date, considering only dates in scope.
measure '# Workdays MTD' =
CALCULATE(
MAX( 'Date'[Workdays MTD] ),
'Date'[IsDateInScope] = TRUE
)
formatString: #,##0
displayFolder: 5. Weekday / Workday\Measures\# Workdays
lineageTag: abc-123
带 formatStringDefinition(动态格式)的度量值
measure 'Sales Target MTD vs. Actuals (%)' =
Comparison.RelativeToTarget (
[Actuals MTD],
[Sales Target MTD]
)
displayFolder: 2. MTD\Sales Target
lineageTag: abc-123
formatStringDefinition =
FormatString.Comparison.RelativeToTarget (
"SUFFIX",
1,
"ARROWS",
"",
""
)
**注意:**通过 DAX 表达式动态计算格式时(通常使用计算组格式函数),formatStringDefinition 会取代 formatString。
其他对象类型
计算列、角色(RLS/OLS)、计算组、日期表标记、层次结构、分区、关系、共享表达式和模型配置的完整示例,请参阅 references/tmdl-file-examples.md。
常见数据质量模式
summarizeBy 规则
| 列类型 | 正确的 summarizeBy | 原因 |
|---|---|---|
| 键(代理键/自然键) | none | 键永不聚合 |
| 属性(名称、代码、类型) | none | 文本属性永不求和 |
| 日期 | none | 日期永不求和 |
| 布尔标志 | none | 标志永不求和 |
| 可加数值事实(金额、数量) | sum | 默认聚合方式为 SUM |
| 不可加数值事实(比率、百分比) | none | 无法进行有意义的求和 |
常见修正模式——将键列的 summarizeBy: sum 改为 summarizeBy: none:
// Before (wrong - key column should not sum)
column 'Customer Key'
dataType: int64
isHidden
lineageTag: abc-123
summarizeBy: sum
sourceColumn: Customer Key
// After (correct)
column 'Customer Key'
dataType: int64
isHidden
lineageTag: abc-123
summarizeBy: none
sourceColumn: Customer Key
formatString 模式
| 数据类型 | 模式 | 示例 |
|---|---|---|
| 整数 | #,##0 | 1,234 |
| 小数(2 位) | #,##0.00 | 1,234.56 |
| 百分比 | #,##0% 或 0.00% | 85% 或 85.00% |
| 货币 | $#,##0.00 | $1,234.56 |
| 日期 | mm/dd/yyyy 或 dd/mm/yyyy | 01/15/2024 |
PBI_FormatHint 注释
Power BI Desktop 可能会在 formatString 旁添加 PBI_FormatHint 注释:
column Amount
dataType: decimal
formatString: #,##0.00
lineageTag: abc-123
summarizeBy: sum
sourceColumn: Amount
annotation SummarizationSetBy = Automatic
annotation PBI_FormatHint = {"isGeneralNumber":true}
**不要尝试移除此注释。**Power BI 工具会自动重新添加。设置 formatString 时,请保留任何已有的 PBI_FormatHint。如果 Power BI 重新添加已移除的 PBI_FormatHint,请接受。
快速参考
属性速查表
如需查看每种对象类型的完整属性参考,请参阅 references/object-properties.md。
| 对象 | 属性 | 值 | 备注 |
|---|---|---|---|
| 列 | dataType | string、int64、double、decimal、dateTime、boolean、binary、unknown、variant、automatic | 数据列必填 |
| 列 | summarizeBy | default、none、sum、min、max、count、average、distinctCount | 键/属性请使用 none |
| 列 | type | data、calculated、rowNumber、calculatedTableColumn | 列类型变体 |
| 列 | isHidden | (标志,无值) | 布尔标志:单独一行仅写关键字 |
| 列 | isKey | (标志,无值) | 将该列标记为表的键 |
| 列 | isNullable | (标志,无值) | 列允许为空值 |
| 列 | isUnique | (标志,无值) | 列值唯一 |
| 列 | isNameInferred | (标志,无值) | 根据源推断名称 |
| 列 | isDefaultLabel | (标志,无值) | 表的默认标签 |
| 列 | isDefaultImage | (标志,无值) | 表的默认图像 |
| 列 | isDataTypeInferred | (标志,无值) | 根据源推断数据类型 |
| 列 | isAvailableInMdx | (标志,无值) | 可用于 MDX 查询 |
| 列 | keepUniqueRows | (标志,无值) | 保留唯一行 |
| 列 | encodingHint | default、hash、value | 存储编码提示 |
| 列 | alignment | default、left、right、center | 列对齐方式 |
| 列 | displayFolder | 文件夹路径字符串 | 使用 \ 表示嵌套:1. Year\Quarter |
| 列 | sourceColumn | 源列名称 | 必须与 Power Query 输出列匹配 |
| 列 | sortByColumn | 列名称引用 | 用于排序的列(例如,按月份编号对月份名称排序) |
| 列 | expression | DAX 表达式 | 用于计算列 |
| 度量值 | formatString | 格式模式 | 例如,#,##0、0.00% |
| 度量值 | displayFolder | 文件夹路径字符串 | 使用 \ 表示嵌套 |
| 度量值 | formatStringDefinition | DAX 表达式块 | 动态格式字符串(替代 formatString) |
| 度量值 | isHidden | (标志,无值) | 隐藏度量值 |
| 度量值 | isSimpleMeasure | (标志,无值) | 简单的隐式样式度量值 |
| 度量值 | dataCategory | 字符串 | 语义数据类别 |
| 分区 | mode | import、directQuery、default、push、dual、directLake | 存储模式 |
| 分区 | sourceType | query、calculated、none、m、entity、policyRange、calculationGroup、inferred | 源类型 |
| 关系 | crossFilteringBehavior | oneDirection、bothDirections、automatic | 交叉筛选方向 |
| 关系 | securityFilteringBehavior | oneDirection、bothDirections、none | RLS 筛选方向 |
| 关系 | fromCardinality / toCardinality | none、one、many | 基数端点 |
| 关系 | isActive | (标志,无值) | 活动关系 |
| 角色 | modelPermission | none、read、readRefresh、refresh、administrator | 角色权限级别 |
| 模型 | discourageImplicitMeasures | (标志,无值) | 禁用隐式度量值 |
| 模型 | defaultPowerBIDataSourceVersion | powerBI_V1、powerBI_V2、powerBI_V3 | PBI 数据源版本 |
| 模型 | directLakeBehavior | automatic、directLakeOnly、directQueryOnly | Direct Lake 模式 |
| 全部 | lineageTag | GUID | 唯一标识符,请勿更改现有值 |
缩进深度概要
规则:多行 DAX 主体的缩进深度始终比其所属对象声明深 2 级。
| 上下文 | 深度 | 制表符 |
|---|---|---|
顶层声明(table、relationship、expression) | 0 | 0 |
| 表属性、列/度量值/层次结构声明 | 1 | 1 |
| 列/度量值属性、层次结构级别 | 2 | 2 |
| 在深度 1 声明的度量值/列的 DAX 主体(位于表内) | 3 | 3 |
| 级别属性 | 3 | 3 |
在深度 0 声明的顶层 function 的 DAX 主体 | 2 | 2 |
calculationGroup 内的 calculationItem(深度 1) | 2 | 2 |
深度 2 的 calculationItem 的 DAX 主体 | 4 | 4 |
其他资源
参考文件
references/object-properties.md- 涵盖 30 多种 TMDL 对象类型的完整属性参考,其中包含每种属性类型的有效枚举值(dataType、summarizeBy、modeType、crossFilteringBehavior 等)references/column-properties.md- 列专属属性指南,涵盖summarizeBy规则、formatString模式和PBI_FormatHint行为references/naming-conventions.md- SQLBI 命名约定、显示文件夹约定、度量值表约定和计算组命名references/bim-to-tmdl.md- 通过 Tabular Editor CLI 或 TOM TmdlSerializer 在model.bim(TMSL)与definition/(TMDL)之间进行转换references/tmdl-file-examples.md- 每种 TMDL 文件类型的完整示例(model、database、expressions、relationships、roles、perspectives、tables、cultures),包括反引号括起的表达式、字段参数、计算组和日期表
获取文档
如需获取最新的 TMDL 参考文档,请搜索 https://learn.microsoft.com 并获取相关页面。根据用户的请求进行搜索,并按需执行多次搜索,以确保在继续操作前获得充分的上下文。
示例模型
examples/SpaceParts.SemanticModel/—— 完整的真实 TMDL 模型(SpaceParts),包含 40 个表、152 个度量值、8 个计算组、8 个 RLS 角色、2 个透视,以及 DAX UDF(functions.tmdl)、共享 M 表达式、关系和区域设置。涵盖所有 TMDL 文件类型。值得查看的关键文件:definition/functions.tmdl—— 带参数、类型和多行表达式的 DAX 用户定义函数definition/tables/Z04CG1 - Time Intelligence.tmdl—— 带三重反引号 DAX 的计算组definition/tables/__Measures.tmdl—— 带计算组引用的度量值表definition/tables/Invoices.tmdl—— 大型事实表(51 个度量值,18 列)definition/tables/Date.tmdl—— 包含 42 列的计算日期表definition/roles/Account Managers.tmdl—— 带 DAX 筛选器表达式的 RLS 角色definition/relationships.tmdl—— 27 个关系,其中包括非活动关系definition/expressions.tmdl—— 共享 M/Power Query 表达式和参数definition/perspectives/Measure Selection.tmdl—— 透视定义