tmdl について
tmdl は、PBIP プロジェクト内の TMDL ファイルを直接編集するためのガイダンススキルです。Tabular Editor CLI、Power BI MCP サーバー、connect-pbid が使えない場合を対象とし、DAX や参照整合性は直接編集では検証されない点も説明します。
主な機能
- 01テーブル、列、メジャー、リレーションシップの編集ガイド
- 02インデント、命名、プロパティ順の規則
- 03DAX と説明文の TMDL 記述例
- 04ファイル種別とオブジェクト階層の概要
- 05直接編集時の検証上の注意点
活用シーン
- 01Git リポジトリ内の PBIP モデルファイルの編集
- 02説明や書式文字列の簡易変更
- 03TMDL メジャーの追加や変更
- 04TMDL 構文規則の確認
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(Tabular Model Definition Language)ファイルを直接作成、編集するための専門的なガイダンスです。
このスキルは最終手段です。 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 経由でデプロイするときです。PBI Desktop で開く前に、
pbip-validatorエージェントを使用して、TMDL ファイルの構文上の問題、インデントエラー、参照整合性を確認してください。
このスキルを使用するタイミング
Tabular Editor CLI、Power BI MCP サーバー、または connect-pbid スキルを利用できず、次の作業を行う場合にのみ有効にしてください。
.tmdlファイルを直接編集する(メジャー、列、テーブル、リレーションシップ)- TMDL でメジャー定義を追加、変更する
- 列、メジャー、テーブルに説明を追加する
summarizeByまたはformatStringの値を修正する- TMDL の構文規則(インデント、引用符、プロパティの順序)を理解する
- 複数行の DAX を TMDL 形式で記述する
///の説明と//のコメントの違いを理解する
重要事項
///(スラッシュ3つ)は、直後に続くオブジェクトのDescriptionプロパティを設定します。///の行の直後には、宣言(measure、column、tableなど)を置く必要があります。空行や別の///を置かないでください。通常のコメントには//を使用します。- インデントには意味があります。 TMDL では、空白によるインデントの深さがネストのレベルを示します(TMDL spec — Indentation)。PBIP ファイルでは、Power BI Desktop と TOM の
TmdlSerializerの既定値がIndentationMode.Tabsのため、1 レベルにつきタブを1つ使用します。スペースも有効です(IndentationMode.Spaces。既定では1レベルにつき4つ)が、ファイル内で統一してください。インデントが混在したり正しくなかったりすると、モデルが壊れます。テーブルのプロパティは1レベル、テーブルに属する列のプロパティは2レベルインデントします。 - 名前の引用符に関する規則: スペースや特殊文字を含む名前、または数字で始まる名前に限り、引用符で囲みます。単純な名前やアンダースコアで始まる名前は引用符で囲みません。詳細は「名前の引用符」セクションを参照してください。
- M 式とテーブルは同じ名前空間を共有します。
expressions.tmdlのexpression <name>で宣言された名前と、tables/*.tmdlのtable <name>で宣言された名前が重複すると、Power BI Desktop の読み込みに失敗し、'duplicate member <name>'が発生します。異なる名前を付けてください。一般的な修正方法は、M 式にQueryまたはSourceを接尾辞として付け、source = #"<Name> Query"を介してパーティションから参照することです。validate_pbip.pyはこれを ERROR として検出します。
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 | セキュリティロールごとに 1 つのファイル(RLS フィルター、ロールメンバー、OLS) | definition/roles/ |
perspectives/<Name>.tmdl | パースペクティブごとに 1 つのファイル(オブジェクトの所属) | 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 ファイルではレベルごとに 1 つのタブを使用します(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、calculationItems では深さ 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
規則:
///の次の行には、宣言を直ちに記述する必要があります///と宣言の間に空行を入れてはいけません- 複数の
///行は 1 つの説明に連結されます ///は次の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、description)については、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 には 2 つの構文があります:
1. インデントブロック(最も一般的) -- 式本体を宣言より 2 レベル深くインデントします:
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
インデントブロック構文(標準的なアプローチ) -- メジャーの親(テーブル)レベルからさらに 2 つのタブでインデントします:
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",
"",
""
)
注: formatStringDefinition は、DAX 式を介して書式が動的に計算される場合(多くの場合、計算グループの書式関数)に 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 をそのままにしておいてください。削除した PBI_FormatHint を Power BI が再追加した場合は、それを受け入れてください。
クイックリファレンス
プロパティ早見表
各オブジェクト型のプロパティを網羅したリファレンスについては、**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 | (フラグ、値なし) | 列でNULL値を許可します |
| 列 | 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(深さ 1)内の calculationItem | 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/-- 40 個のテーブル、152 個のメジャー、8 個の計算グループ、8 個の RLS ロール、2 個のパースペクティブ、DAX UDF(functions.tmdl)、共有 M 式、リレーションシップ、カルチャを含む、実際の TMDL モデル(SpaceParts)の完全な例。すべての 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-- パースペクティブの定義