Analysis-Services/BestPracticeRules/Japanese/BPARules.json

678 lines
57 KiB
JSON
Raw Normal View History

2022-11-22 17:49:30 +08:00
[
{
"ID": "AVOID_FLOATING_POINT_DATA_TYPES",
"Name": "[パフォーマンス]浮動小数点データ型を使用しない",
"Category": "パフォーマンス",
"Description": "浮動小数点データ型の「10進数」は、予測できない丸めの誤差が発生したり、特定のシナリオでパフォーマンスが低下したりする可能性があるため、避けたほうがよいでしょう。可能な場合は、「整数」または「固定小数点」を使用してください「固定小数点」は10進記号の後の4桁に制限されています",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "DataType = \"Double\"",
"FixExpression": "DataType = DataType.Decimal",
"CompatibilityLevel": 1200
},
{
"ID": "ISAVAILABLEINMDX_FALSE_NONATTRIBUTE_COLUMNS",
"Name": "[パフォーマンス]属性以外の列非表示列や階層に使用しない列数値列でIsAvailableInMdxをfalseに設定",
"Category": "パフォーマンス",
"Description": "処理時間を短縮し、処理後のメモリを節約するために、MDX クライアントでフィルターとして使用されることのない列に対しては、属性階層を構築しないようにします。つまり、「列で並べ替え」として使用されない、またはユーザ階層で参照されないすべての非表示列は、その IsAvailableInMdx プロパティを false に設定しておくと良い。参考: https://blog.crossjoin.co.uk/2018/07/02/isavailableinmdx-ssas-tabular/",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "IsAvailableInMDX\r\nand\r\n\n(IsHidden or Table.IsHidden)\r\nand\r\n\nnot UsedInSortBy.Any() \r\nand\r\n\nnot UsedInHierarchies.Any()\r\nand\r\nnot UsedInVariations.Any()",
"FixExpression": "IsAvailableInMDX = false",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_BI-DIRECTIONAL_RELATIONSHIPS_AGAINST_HIGH-CARDINALITY_COLUMNS",
"Name": "[パフォーマンス]カーディナリティの高い列に対する双方向のリレーションシップを避ける",
"Category": "パフォーマンス",
"Description": "最高のパフォーマンスを得るためには、高カーディナリティの列に対して双方向のリレーションシップを使用しないことをお勧めします。このルールを実行するには、まずここに示すスクリプトを実行する必要があります。https://www.elegantbi.com/post/vertipaqintabulareditor",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "UsedInRelationships.Any(CrossFilteringBehavior == CrossFilteringBehavior.BothDirections)\n\nand\n\nConvert.ToInt64(GetAnnotation(\"Vertipaq_Cardinality\")) > 100000",
"CompatibilityLevel": 1200
},
{
"ID": "REDUCE_USAGE_OF_LONG-LENGTH_COLUMNS_WITH_HIGH_CARDINALITY",
"Name": "[パフォーマンス]カーディナリティの高い長文列の使用を減らす",
"Category": "パフォーマンス",
"Description": "長文のテキスト列は避けた方が良いでしょう。特に、ユニークな値が多い列の場合には注意が必要です。このようなタイプの列は、処理時間が長くなったり、モデルサイズが肥大化したり、ユーザーのクエリが遅くなったりする原因となります。長文とは、100文字以上と定義されます",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "Convert.ToInt64(GetAnnotation(\"LongLengthRowCount\")) > 500000",
"CompatibilityLevel": 1200
},
{
"ID": "SPLIT_DATE_AND_TIME",
"Name": "[パフォーマンス]日付と時刻を分割する",
"Category": "パフォーマンス",
"Description": "このルールは、midnight表示2022/11/01 0:00:00ではない値を持つdatetime列を検索します。パフォーマンスを最大化するためには、time要素をdate要素から分離する必要がありますまたは、列のカーディナリティを減らすために、time要素をmidnight表示に丸める必要があります。参考: https://www.sqlbi.com/articles/separate-date-and-time-in-powerpivot-and-bism-tabular/",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "Convert.ToInt32(GetAnnotation(\"DateTimeWithHourMinSec\")) > 0",
"CompatibilityLevel": 1200
},
{
"ID": "LARGE_TABLES_SHOULD_BE_PARTITIONED",
"Name": "[パフォーマンス]大きなテーブルはパーティションを行う",
"Category": "パフォーマンス",
"Description": "大きなテーブルは、処理を最適化するためにパーティショニングする必要があります。このルールを正しく実行するためには、ここに示すスクリプトを実行する必要があります。https://www.elegantbi.com/post/vertipaqintabulareditor",
"Severity": 2,
"Scope": "Table",
"Expression": "Convert.ToInt64(GetAnnotation(\"Vertipaq_RowCount\")) > 25000000\r\nand\r\nPartitions.Count = 1",
"CompatibilityLevel": 1200
},
{
"ID": "REDUCE_USAGE_OF_CALCULATED_COLUMNS_THAT_USE_THE_RELATED_FUNCTION",
"Name": "[パフォーマンス] RELATED関数を使用する計算列の使用を減らす",
"Category": "パフォーマンス",
"Description": "計算列は、Power Queryから読み込まれた状態のデータ列ほど圧縮されないため、処理時間が長くなる可能性があります。そのため、計算列は必要に応じて使用し、不必要に増やさないことが肝要です。RELATED関数を使用している場合は、避けた方が良いかもしれません。参照: https://www.sqlbi.com/articles/storage-differences-between-calculated-columns-and-calculated-tables/",
"Severity": 2,
"Scope": "CalculatedColumn",
"Expression": "RegEx.IsMatch(Expression,\"(?i)RELATED\\s*\\(\")",
"CompatibilityLevel": 1200
},
{
"ID": "SNOWFLAKE_SCHEMA_ARCHITECTURE",
"Name": "[パフォーマンス]スノーフレークの代わりにスタースキーマを検討",
"Category": "パフォーマンス",
"Description": "一般的に、Tabular ModelPower BIやAnalysis Services等のデータモデルにはスタースキーマが最適なアーキテクチャです。とはいえ、スーフレーク・アプローチを使用する有効なケースもあります。お使いのモデルをチェックして、スタースキーマ・アーキテクチャへの移行をご検討ください。参考: https://docs.microsoft.com/en-us/power-bi/guidance/star-schema",
"Severity": 2,
"Scope": "Table, CalculatedTable",
"Expression": "UsedInRelationships.Any(current.Name == FromTable.Name)\r\nand\r\nUsedInRelationships.Any(current.Name == ToTable.Name)",
"CompatibilityLevel": 1200
},
{
"ID": "MODEL_SHOULD_HAVE_A_DATE_TABLE",
"Name": "[パフォーマンス]データモデルには日付テーブルが必要",
"Category": "パフォーマンス",
"Description": "一般的に、モデルは日付テーブルを持つべきです。日付テーブルを持たないモデルは、タイムインテリジェンス関数などの機能を利用していないか、適切な構造のアーキテクチャを持っていない可能性があります",
"Severity": 2,
"Scope": "Model",
"Expression": "Tables.Any(DataCategory == \"Time\" && Columns.Any(IsKey == true && DataType == \"DateTime\")) == false",
"CompatibilityLevel": 1200
},
{
"ID": "DATE/CALENDAR_TABLES_SHOULD_BE_MARKED_AS_A_DATE_TABLE",
"Name": "[パフォーマンス]日​​付/カレンダーテーブルは「日付テーブルとしてマーク」を行う",
"Category": "パフォーマンス",
"Description": "このルールでは、「date」または「calendar」という言葉を含むテーブルを探し、日付テーブルとしてマークされる可能性が高いと考えられます※テーブル名が英語の場合に限る。参考: https://docs.microsoft.com/power-bi/transform-model/desktop-date-tables",
"Severity": 2,
"Scope": "Table, CalculatedTable",
"Expression": "(Name.ToUpper().Contains(\"DATE\") or Name.ToUpper().Contains(\"CALENDAR\"))\n\nand\n\n(\nDataCategory <> \"Time\"\n\nor\n\nColumns.Any(IsKey == true && DataType == \"DateTime\") == false\n)",
"CompatibilityLevel": 1200
},
{
"ID": "REMOVE_AUTO-DATE_TABLE",
"Name": "[パフォーマンス]自動の日付/時刻テーブルを削除",
"Category": "パフォーマンス",
"Description": "自動日付表示のテーブルを使用しないようにします。Power BI Desktopの設定で、自動日付表示のテーブルを必ずオフにしてくださいPower BIにて日付テーブルを使う際のベストプラクティス。これにより、メモリリソースが節約できます。参考 https://www.youtube.com/watch?v=xu3uDEHtCrg",
"Severity": 2,
"Scope": "Table, CalculatedTable",
"Expression": "ObjectTypeName == \"Calculated Table\"\n\r\nand\r\n\n(\nName.StartsWith(\"DateTableTemplate_\") \n\nor \n\nName.StartsWith(\"LocalDateTable_\")\n)",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_EXCESSIVE_BI-DIRECTIONAL_OR_MANY-TO-MANY_RELATIONSHIPS",
"Name": "[パフォーマンス]過度の双方向リレーションシップや多対多リレーションシップを回避",
"Category": "パフォーマンス",
"Description": "双方向および多対多のリレーションシップの使用を制限することを推奨します。本ルールは、リレーションシップの30%以上が双方向または多対多である場合、フラグが立てられます。参考: https://www.sqlbi.com/articles/bidirectional-relationships-and-ambiguity-in-dax/",
"Severity": 2,
"Scope": "Model",
"Expression": "(\r\n\nRelationships.Where(CrossFilteringBehavior == CrossFilteringBehavior.BothDirections).Count()\r\n\n+\r\n\nRelationships.Where(FromCardinality.ToString() == \"Many\" && ToCardinality.ToString() == \"Many\").Count()\r\n\n)\r\n\n\n/\r\n\n\nMath.Max(Convert.ToDecimal(Relationships.Count)\n\n,1)> 0.3",
"CompatibilityLevel": 1200
},
{
"ID": "LIMIT_ROW_LEVEL_SECURITY_(RLS)_LOGIC",
"Name": "[パフォーマンス]行レベルのセキュリティRLSロジックを制限",
"Category": "パフォーマンス",
"Description": "行レベルのセキュリティに使用するDAX式をシンプルにすることを心掛ける。これにより、上流システムデータウェアハウスにオフロード処理される可能性が高い",
"Severity": 2,
"Scope": "Table, CalculatedTable",
"Expression": "RowLevelSecurity.Any(RegEx.IsMatch(it.Replace(\" \",\"\"),\"(?i)RIGHT\\s*\\(\"))\r\nor\r\nRowLevelSecurity.Any(RegEx.IsMatch(it.Replace(\" \",\"\"),\"(?i)LEFT\\s*\\(\"))\r\nor\r\nRowLevelSecurity.Any(RegEx.IsMatch(it.Replace(\" \",\"\"),\"(?i)UPPER\\s*\\(\"))\r\nor\r\nRowLevelSecurity.Any(RegEx.IsMatch(it.Replace(\" \",\"\"),\"(?i)LOWER\\s*\\(\"))\r\nor\r\nRowLevelSecurity.Any(RegEx.IsMatch(it.Replace(\" \",\"\"),\"(?i)FIND\\s*\\(\"))\r\n",
"CompatibilityLevel": 1200
},
{
"ID": "MODEL_USING_DIRECT_QUERY_AND_NO_AGGREGATIONS",
"Name": "[パフォーマンス] Power BIでDirectQueryを使用する場合は、「ユーザー定義集計」の使用を検討する。",
"Category": "パフォーマンス",
"Description": "Power BI Premium で DirectQuery を使用する場合、パフォーマンスを向上させるために「集計」の利用を検討することをお勧めします。 参考https://docs.microsoft.com/power-bi/transform-model/desktop-aggregations",
"Severity": 1,
"Scope": "Model",
"Expression": "Tables.Any(ObjectTypeName == \"Table (DirectQuery)\")\r\nand\r\n\n\nAllColumns.Any(AlternateOf != null) == false\r\nand \r\nDefaultPowerBIDataSourceVersion.ToString() == \"PowerBI_V3\"",
"CompatibilityLevel": 1200
},
{
"ID": "MINIMIZE_POWER_QUERY_TRANSFORMATIONS",
"Name": "[パフォーマンス] PowerQueryによる変換を最小限に抑える",
"Category": "パフォーマンス",
"Description": "モデル処理のパフォーマンスを向上させるために、Power Query の変換を最小限に抑えます。可能であれば、これらの変換をデータウェアハウスにオフロード(処理)することがベストプラクティスとなります。また、モデル内でクエリフォールディングが行われているかどうかを確認してください。クエリフォルディングの詳細については、以下の記事を参照してください。 参考https://docs.microsoft.com/power-query/power-query-folding",
"Severity": 2,
"Scope": "Partition",
"Expression": "\nSourceType.ToString() = \"M\"\r\nand\r\n(\r\nQuery.Contains(\"Table.Combine(\")\r\nor\r\n\nQuery.Contains(\"Table.Join(\")\r\nor\r\n\nQuery.Contains(\"Table.NestedJoin(\")\r\nor\r\nQuery.Contains(\"Table.AddColumn(\")\r\nor\r\nQuery.Contains(\"Table.Group(\")\r\nor\r\nQuery.Contains(\"Table.Sort(\")\r\nor\r\nQuery.Contains(\"Table.Pivot(\")\r\nor\r\nQuery.Contains(\"Table.Unpivot(\")\r\nor\r\nQuery.Contains(\"Table.UnpivotOtherColumns(\")\r\nor\r\nQuery.Contains(\"Table.Distinct(\")\r\nor\r\nQuery.Contains(\"[Query=\"\"SELECT\")\r\nor\r\nQuery.Contains(\"Value.NativeQuery\")\r\nor\r\nQuery.Contains(\"OleDb.Query\")\r\nor\r\nQuery.Contains(\"Odbc.Query\")\r\n)",
"CompatibilityLevel": 1200
},
{
"ID": "UNPIVOT_PIVOTED_(MONTH)_DATA",
"Name": "[パフォーマンス]クロス集計された(月の)データのピボット解除を行う",
"Category": "パフォーマンス",
"Description": "テーブルにピボット形式のデータ(クロス集計書式のデータ)を使用しないようにします。このルールは、特に月ごとのピボットデータをチェックします。参考: https://www.elegantbi.com/post/top10bestpractices",
"Severity": 2,
"Scope": "Table, CalculatedTable",
"Expression": "Columns.Any(Name.ToUpper().Contains(\"JAN\") && (DataType == DataType.Int64 || DataType == DataType.Decimal || DataType == DataType.Double))\nand\nColumns.Any(Name.ToUpper().Contains(\"FEB\") && (DataType == DataType.Int64 || DataType == DataType.Decimal || DataType == DataType.Double))\nand\nColumns.Any(Name.ToUpper().Contains(\"MAR\") && (DataType == DataType.Int64 || DataType == DataType.Decimal || DataType == DataType.Double))\nand\nColumns.Any(Name.ToUpper().Contains(\"APR\") && (DataType == DataType.Int64 || DataType == DataType.Decimal || DataType == DataType.Double))\nand\nColumns.Any(Name.ToUpper().Contains(\"MAY\") && (DataType == DataType.Int64 || DataType == DataType.Decimal || DataType == DataType.Double))\nand\nColumns.Any(Name.ToUpper().Contains(\"JUN\") && (DataType == DataType.Int64 || DataType == DataType.Decimal || DataType == DataType.Double))",
"CompatibilityLevel": 1200
},
{
"ID": "MANY-TO-MANY_RELATIONSHIPS_SHOULD_BE_SINGLE-DIRECTION",
"Name": "[パフォーマンス]多対多のリレーションシップは単一方向にする",
"Category": "パフォーマンス",
"Severity": 2,
"Scope": "Relationship",
"Expression": "FromCardinality == \"Many\"\nand\nToCardinality == \"Many\"\nand\nCrossFilteringBehavior == \"BothDirections\"",
"CompatibilityLevel": 1200,
"Description": ""
},
{
"ID": "REDUCE_USAGE_OF_CALCULATED_TABLES",
"Name": "[パフォーマンス]計算テーブルの使用を減らす",
"Category": "パフォーマンス",
"Description": "計算テーブルのロジックをデータウェアハウスDWHに移行する=DWHで処理させる。計算テーブルに依存していると、技術的負債が発生し、プラットフォーム上に複数のモデルがある場合には、潜在的な不整合ズレにつながります",
"Severity": 2,
"Scope": "CalculatedTable",
"Expression": "1=1",
"CompatibilityLevel": 1200
},
{
"ID": "REMOVE_REDUNDANT_COLUMNS_IN_RELATED_TABLES",
"Name": "[パフォーマンス]関連テーブルの冗長な列を削除",
"Category": "パフォーマンス",
"Description": "不要な列を削除することでモデルサイズを軽減したり、データの読み込み速度が早くなります",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "UsedInRelationships.Any() == false \r\nand\r\nModel.AllColumns.Any(Name == current.Name and Table.Name != current.Table.Name and Table.UsedInRelationships.Any(FromTable.Name == current.Table.Name))",
"CompatibilityLevel": 1200
},
{
"ID": "MEASURES_USING_TIME_INTELLIGENCE_AND_MODEL_IS_USING_DIRECT_QUERY",
"Name": "[パフォーマンス]メジャーはタイムインテリジェンス関数使用、モデルはDirectQueryを使用している",
"Category": "パフォーマンス",
"Description": "現在、DirectQueryを使用した場合、タイムインテリジェンス関数ではパフォーマンスの低下が知られています。パフォーマンスの問題がある場合は、ファクト・テーブルに前年または前月のデータを示す列を追加するなど、別の解決策を試すとよいでしょう",
"Severity": 2,
"Scope": "Measure, CalculationItem",
"Expression": "Model.Tables.Any(ObjectTypeName == \"Table (DirectQuery)\")\r\nand\r\n(\r\nRegEx.IsMatch(Expression,\"CLOSINGBALANCEMONTH\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"CLOSINGBALANCEQUARTER\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"CLOSINGBALANCEYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"DATEADD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"DATESBETWEEN\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"DATESINPERIOD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"DATESMTD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"DATESQTD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"DATESYTD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"ENDOFMONTH\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"ENDOFQUARTER\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"ENDOFYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"FIRSTDATE\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"FIRSTNONBLANK\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"FIRSTNONBLANKVALUE\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"LASTDATE\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"LASTNONBLANK\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"LASTNONBLANKVALUE\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"NEXTDAY\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"NEXTMONTH\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"NEXTQUARTER\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"NEXTYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"OPENINGBALANCEMONTH\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"OPENINGBALANCEQUARTER\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"OPENINGBALANCEYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"PARALLELPERIOD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"PREVIOUSDAY\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"PREVIOUSMONTH\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"PREVIOUSQUARTER\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"PREVIOUSYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"SAMEPERIODLASTYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"STARTOFMONTH\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"STARTOFQUARTER\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"STARTOFYEAR\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"TOTALMTD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"TOTALQTD\\s*\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"TOTALYTD\\s*\\(\")\r\n)",
"CompatibilityLevel": 1200
},
{
"ID": "REDUCE_NUMBER_OF_CALCULATED_COLUMNS",
"Name": "[パフォーマンス]計算列の数を減らす",
"Category": "パフォーマンス",
"Description": "計算列は、データ列Power Queryから読み込まれた状態の列のように圧縮されないため、より多くのメモリを消費します。また、テーブルとプロセスの再計算の両方で処理時間が長くなります。計算列のロジックをデータウェアハウスにオフロードして、計算列をデータ列に変えましょう。参考: https://www.elegantbi.com/post/top10bestpractices",
"Severity": 2,
"Scope": "Model",
"Expression": "AllColumns.Where(Type.ToString() == \"Calculated\").Count() > 5",
"CompatibilityLevel": 1200
},
{
"ID": "CHECK_IF_BI-DIRECTIONAL_AND_MANY-TO-MANY_RELATIONSHIPS_ARE_VALID",
"Name": "[パフォーマンス]双方向および多対多のリレーションシップが有効かどうかを確認",
"Category": "パフォーマンス",
"Description": "双方向や多対多のリレーションシップは、パフォーマンスを低下させたり、意図しない結果をもたらすことがあります。これらの特定のリレーションシップが設計通りに機能しているか、実際に必要かどうかを必ず確認してください。\n参考 https://www.sqlbi.com/articles/bidirectional-relationships-and-ambiguity-in-dax/",
"Severity": 1,
"Scope": "Relationship",
"Expression": "FromCardinality.ToString() = \"Many\" and ToCardinality.ToString() = \"Many\"\r\nor\r\nCrossFilteringBehavior == CrossFilteringBehavior.BothDirections",
"CompatibilityLevel": 1200
},
{
"ID": "CHECK_IF_DYNAMIC_ROW_LEVEL_SECURITY_(RLS)_IS_NECESSARY",
"Name": "[パフォーマンス]動的行レベルセキュリティRLSが必要かどうかを確認",
"Category": "パフォーマンス",
"Description": "動的な行レベルのセキュリティRLSを使用すると、メモリやパフォーマンスのオーバーヘッドが増える可能性があります。使用する際には、そのメリット・デメリットをよく調べてください。参考 https://docs.microsoft.com/power-bi/admin/service-admin-rls",
"Severity": 1,
"Scope": "Table, CalculatedTable",
"Expression": "RegEx.IsMatch(Expression,\"(?i)USERNAME\\(\")\r\nor\r\nRegEx.IsMatch(Expression,\"(?i)USERPRINCIPALNAME\\(\")",
"CompatibilityLevel": 1200
},
{
"ID": "DAX_COLUMNS_FULLY_QUALIFIED",
"Name": "[DAX式]列の参照はテーブル名[列名]になっていること",
"Category": "DAX式",
"Description": "完全修飾列参照を使用すると、列参照とメジャー参照の区別が容易になり、特定のエラーを回避することができます。DAX で列を参照する場合は、まずテーブル名を指定し、次に角括弧で列名を指定します(テーブル名[列名])。参考: https://www.elegantbi.com/post/top10bestpractices",
"Severity": 3,
"Scope": "Measure, KPI, TablePermission, CalculationItem",
"Expression": "DependsOn.Any(Key.ObjectType = \"Column\" and Value.Any(not FullyQualified))",
"CompatibilityLevel": 1200
},
{
"ID": "DAX_MEASURES_UNQUALIFIED",
"Name": "[DAX式]メジャー参照はテーブル名を前に入れない",
"Category": "DAX式",
"Description": "非修飾メジャー参照を使用すると、列参照とメジャー参照の区別が容易になり、特定のエラーを回避することができます。DAX を使用してメジャーを参照する場合は、テーブル名を指定しないでください。メジャー参照の場合、[メジャー名]のみで参照を行います。参考: https://www.elegantbi.com/post/top10bestpractices",
"Severity": 3,
"Scope": "Measure, CalculatedColumn, CalculatedTable, KPI, CalculationItem",
"Expression": "DependsOn.Any(Key.ObjectType = \"Measure\" and Value.Any(FullyQualified))",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_DUPLICATE_MEASURES",
"Name": "[DAX式] 2つのメジャーで同じ定義を持たせないこと",
"Category": "DAX式",
"Description": "異なる名前の2つのメジャーで、同じDAX式で定義したメジャーは避けるべきです",
"Severity": 2,
"Scope": "Measure",
"Expression": "Model.AllMeasures.Any(Expression.Replace(\" \",\"\").Replace(\"\\n\",\"\").Replace(\"\\r\",\"\").Replace(\"\\t\",\"\") = outerIt.Expression.Replace(\" \",\"\").Replace(\"\\n\",\"\").Replace(\"\\r\",\"\").Replace(\"\\t\",\"\") and it <> outerIt)",
"CompatibilityLevel": 1200
},
{
"ID": "USE_THE_TREATAS_FUNCTION_INSTEAD_OF_INTERSECT",
"Name": "[DAX式]仮想リレーションシップにINTERSECTの代わりにTREATAS関数を使用する",
"Category": "DAX式",
"Description": "TREATAS関数は、仮想リレーションシップで使用した場合、INTERSECT関数よりも効率的で優れた性能を発揮します。参考 https://www.sqlbi.com/articles/propagate-filters-using-treatas-in-dax/",
"Severity": 2,
"Scope": "Measure, CalculationItem",
"Expression": "RegEx.IsMatch(Expression,\"(?i)INTERSECT\\s*\\(\")",
"CompatibilityLevel": 1400
},
{
"ID": "USE_THE_DIVIDE_FUNCTION_FOR_DIVISION",
"Name": "[DAX式]割り算にはDIVIDE関数を使用する",
"Category": "DAX式",
"Description": "除算演算子「/」を使用する代わりに、DIVIDE関数を使用してください。DIVIDE関数は、ゼロ除算のケースエラー値の発生を防ぐを解決してくれます。そのため、エラーを避けるためにも使用することをお勧めします。 \n参考 https://docs.microsoft.com/power-bi/guidance/dax-divide-function-operator",
"Severity": 2,
"Scope": "Measure, CalculatedColumn, CalculationItem",
"Expression": "RegEx.IsMatch(Expression,\"\\]\\s*\\/(?!\\/)(?!\\*)\")\r\nor\r\nRegEx.IsMatch(Expression,\"\\)\\s*\\/(?!\\/)(?!\\*)\")",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_USING_THE_IFERROR_FUNCTION",
"Name": "[DAX式]IFERROR関数の使用を避ける",
"Category": "DAX式",
"Description": "IFERROR関数は、パフォーマンスの低下を招く可能性があるため、使用しないでください。ゼロ除算のエラーが気になる場合は、DIVIDE関数を使用してください。DIVIDE関数は、このようなエラーを空白として自然に解決しますまたは、このようなエラーが発生した場合に何を表示するかをカスタマイズできます。参考 https://www.elegantbi.com/post/top10bestpractices",
"Severity": 2,
"Scope": "Measure, CalculatedColumn",
"Expression": "RegEx.IsMatch(Expression,\"(?i)IFERROR\\s*\\(\")",
"CompatibilityLevel": 1200
},
{
"ID": "MEASURES_SHOULD_NOT_BE_DIRECT_REFERENCES_OF_OTHER_MEASURES",
"Name": "[DAX式]1つのメジャーが他のメジャーを直接参照しない",
"Category": "DAX式",
"Description": "このルールでは、別のメジャーを単に参照しているメジャーを識別します。例として、2 つのメジャーを持つモデルを考えてみましょう。[MeasureA]と[MeasureB]があります。MeasureB の DAX が MeasureB:=[MeasureA] である場合、このルールは MeasureB に対してトリガされます。このような重複したメジャーは削除する必要があります",
"Severity": 2,
"Scope": "Measure",
"Expression": "Model.AllMeasures.Any(DaxObjectName == current.Expression)",
"CompatibilityLevel": 1200
},
{
"ID": "FILTER_COLUMN_VALUES",
"Name": "[DAX式]適切な構文で列値をフィルタリングする",
"Category": "DAX式",
"Description": "CALCULATEまたはCALCULATETABLE関数のフィルター・パラメータに、このパターンFILTER('Table','Table'[Column]=\"Value\")を使用する代わりに、以下のオプションのいずれかを使用してください。KEEPFILTERS関数を使用するかどうかについては、以下の2番目の参考リンクを参照してください。\nオプション1 KEEPFILTERS('Table'[Column]=\"Value\")\nオプション2 'Table'[Column]=\"Value\"\n参考 https://docs.microsoft.com/power-bi/guidance/dax-avoid-avoid-filter-as-filter-argument\n参考 https://www.sqlbi.com/articles/using-keepfilters-in-dax/",
"Severity": 2,
"Scope": "Measure, CalculatedColumn, CalculationItem",
"Expression": "RegEx.IsMatch(Expression,\"(?i)CALCULATE\\s*\\(\\s*[^,]+,\\s*(?i)FILTER\\s*\\(\\s*\\'*[A-Za-z0-9 _]+'*\\s*,\\s*\\'*[A-Za-z0-9 _]+\\'*\\[[A-Za-z0-9 _]+\\]\")\r\nor\r\nRegEx.IsMatch(Expression,\"(?i)CALCULATETABLE\\s*\\([^,]*,\\s*(?i)FILTER\\s*\\(\\s*\\'*[A-Za-z0-9 _]+\\'*,\\s*\\'*[A-Za-z0-9 _]+\\'*\\[[A-Za-z0-9 _]+\\]\")",
"CompatibilityLevel": 1200
},
{
"ID": "FILTER_MEASURE_VALUES_BY_COLUMNS",
"Name": "[DAX式]メジャー値をテーブルではなく列でフィルタリングする",
"Category": "DAX式",
"Description": "CALCULATEまたはCALCULATETABLE関数のフィルター・パラメータに、このパターンFILTER('Table',[Measure]>Value)を使用する代わりに、可能であれば以下のオプションのいずれかを使用してください。特定の列でフィルタリングすると、エンジンが処理するテーブルのサイズが小さくなるため、パフォーマンスが速くなります。VALUES関数とALL関数のどちらを使用するかは、必要な測定結果によって異なります。\nオプション 1: FILTER(VALUES('Table'[Column]),[Measure] > Value)\nオプション 2: FILTER(ALL('Table'[Column]),[Measure] > Value)\n参考: https://docs.microsoft.com/power-bi/guidance/dax-avoid-avoid-filter-as-filter-argument",
"Severity": 2,
"Scope": "Measure, CalculatedColumn, CalculationItem",
"Expression": "RegEx.IsMatch(Expression,\"(?i)CALCULATE\\s*\\(\\s*[^,]+,\\s*(?i)FILTER\\s*\\(\\s*\\'*[A-Za-z0-9 _]+\\'*\\s*,\\s*\\[[^\\]]+\\]\")\r\nor\r\nRegEx.IsMatch(Expression,\"(?i)CALCULATETABLE\\s*\\([^,]*,\\s*(?i)FILTER\\s*\\(\\s*\\'*[A-Za-z0-9 _]+\\'*,\\s*\\[\")",
"CompatibilityLevel": 1200
},
{
"ID": "INACTIVE_RELATIONSHIPS_THAT_ARE_NEVER_ACTIVATED",
"Name": "[DAX式]アクティブされることのない非アクティブなリレーションシップ",
"Category": "DAX式",
"Description": "非アクティブなリレーションシップは、USERELATIONSHIP関数を使用してアクティブにします。非アクティブなリレーションシップがこの関数を介してどのメジャーでも参照されていない場合、そのリレーションシップは使用されません。リレーションシップが必要ないのか、この方法でリレーションシップをアクティブにするのかを判断する必要があります。\n参考 https://docs.microsoft.com/power-bi/guidance/relationships-active-inactive\n参考 https://dax.guide/userelationship/",
"Severity": 2,
"Scope": "Relationship",
"Expression": "IsActive == false\r\nand not\r\n(\r\nModel.AllMeasures.Any(RegEx.IsMatch(Expression,\r\n\"(?i)USERELATIONSHIP\\s*\\(\\s*\\'*\" +\r\ncurrent.FromTable.Name + \"\\'*\\[\" + \r\ncurrent.FromColumn.Name + \"\\]\\s*,\\s*\\'*\" +\r\ncurrent.ToTable.Name + \"\\'*\\[\" +\r\ncurrent.ToColumn.Name + \"\\]\"))\r\nor\r\nModel.AllCalculationItems.Any(RegEx.IsMatch(Expression,\r\n\"(?i)USERELATIONSHIP\\s*\\(\\s*\\'*\" +\r\ncurrent.FromTable.Name + \"\\'*\\[\" + \r\ncurrent.FromColumn.Name + \"\\]\\s*,\\s*\\'*\" +\r\ncurrent.ToTable.Name + \"\\'*\\[\" +\r\ncurrent.ToColumn.Name + \"\\]\"))\r\n)",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_USING_'1-(X/Y)'_SYNTAX",
"Name": "[DAX式「1-(x/y)」構文の使用を避ける",
"Category": "DAX式",
"Description": "パーセント計算を実現するために「1-(x/y)」または「1+(x/y)」構文を使用する代わりに、基本的なDAX関数後述を使用してください。\n正しい構文を使用すると、一般的にパフォーマンスが向上します。「1+/-...」の構文は常に値を返しますが、「1+/-...」構文を使用しない解答は値を返しません値が「空白」になる可能性があるため。したがって、「1+/-...」構文は、より多くの行/列を返し、結果としてクエリーの速度が遅くなる可能性があります。 \n例を挙げて説明しましょう。\n避けるべき 1 - SUM ( 'Sales'[CostAmount] ) / SUM( 'Sales'[SalesAmount] ) \nベターな方法 SUM ( 'Sales'[SalesAmount] ) - DIVIDE ( SUM ( 'Sales'[CostAmount] ), SUM ( 'Sales'[SalesAmount] ) )\nベストな方法 VAR x = SUM ( 'Sales'[SalesAmount] ) RETURN x - DIVIDE ( SUM ( 'Sales'[CostAmount] ), x )",
"Severity": 2,
"Scope": "Measure, CalculatedColumn, CalculationItem",
"Expression": "RegEx.IsMatch(Expression,\"[0-9]+\\s*[-+]\\s*[\\(]*\\s*(?i)SUM\\s*\\(\\s*\\'*[A-Za-z0-9 _]+\\'*\\s*\\[[A-Za-z0-9 _]+\\]\\s*\\)\\s*\\/\")\r\nor\r\nRegEx.IsMatch(Expression,\"[0-9]+\\s*[-+]\\s*(?i)DIVIDE\\s*\\(\")",
"CompatibilityLevel": 1200
},
{
"ID": "EVALUATEANDLOG_SHOULD_NOT_BE_USED_IN_PRODUCTION_MODELS",
"Name": "[DAX式EVALUATEANDLOG 関数を本番運用のモデルで使用しない",
"Category": "DAX式",
"Description": "EVALUATEANDLOG関数は、開発/テスト環境でのみ使用することを想定しており、本番モデルでは使用しないでください。参考https://pbidax.wordpress.com/2022/08/16/introduce-the-dax-evaluateandlog-function/",
"Severity": 1,
"Scope": "Measure",
"Expression": "RegEx.IsMatch(Expression,\"(?i)EVALUATEANDLOG\\s*\\(\")",
"CompatibilityLevel": 1200
},
{
"ID": "DATA_COLUMNS_MUST_HAVE_A_SOURCE_COLUMN",
"Name": "[エラー防止]データ列にはソース列が必要",
"Category": "エラー防止",
"Description": "データ列にはソース列(例:データベースからの列)が必要です。ソース列のないデータ列は、モデルを処理する際にエラーになります",
"Severity": 3,
"Scope": "DataColumn",
"Expression": "string.IsNullOrWhitespace(SourceColumn)",
"CompatibilityLevel": 1200
},
{
"ID": "EXPRESSION_RELIANT_OBJECTS_MUST_HAVE_AN_EXPRESSION",
"Name": "[エラー防止]式に依存するオブジェクトには式が必要",
"Category": "エラー防止",
"Description": "計算列、計算項目(Calculation Items)、およびメジャーには、式が必要です。式がない場合、これらのオブジェクトには値が表示されません",
"Severity": 3,
"Scope": "Measure, CalculatedColumn, CalculationItem",
"Expression": "string.IsNullOrWhiteSpace(Expression)",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_STRUCTURED_DATA_SOURCES_WITH_PROVIDER_PARTITIONS",
"Name": "[エラー防止]プロバイダーパーティションのある構造化データソースを避ける",
"Category": "エラー防止",
"Description": "Power BIは、構造化データソースを参照するプロバイダ別名「レガシー」パーティションをサポートしません。構造化データソースを参照するパーティションは、M言語を使用する必要があります。それ以外の場合、「プロバイダー」パーティションは「プロバイダー」データソースを参照する必要があります。この問題は、構造化データソースをプロバイダデータソースに変換することで解決できます (以下の 2 番目の参照リンクを参照)。\n参考1 https://docs.microsoft.com/power-bi/admin/service-premium-connect-tools#data-source-declaration\n参考2 https://learn.microsoft.com/azure/analysis-services/analysis-services-datasource#understanding-providers \n参考資料 https://www.elegantbi.com/post/convertdatasources",
"Severity": 2,
"Scope": "Partition",
"Expression": "SourceType == \"Query\"\r\nand\r\nDataSource.Type == \"Structured\"",
"CompatibilityLevel": 1200
},
{
"ID": "AVOID_THE_USERELATIONSHIP_FUNCTION_AND_RLS_AGAINST_THE_SAME_TABLE",
"Name": "[エラー防止]USERELATIONSHIP関数とRLSを同じテーブルに対して行うのを避ける",
"Category": "エラー防止",
"Description": "USERELATIONSHIP関数は、行レベルのセキュリティ (RLS) を利用しているテーブルに対して使用できません。この場合、ビジュアルで特定のメジャーを使用する際にエラーが発生します。このルールにより、メジャーのUSERELATIONSHIP関数で使用されているテーブルと RLS がハイライト表示されます。参照: https://blog.crossjoin.co.uk/2013/05/10/userelationship-and-tabular-row-security/",
"Severity": 3,
"Scope": "Table, CalculatedTable",
"Expression": "Model.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)USERELATIONSHIP\\s*\\(\\s*.+?(?=])\\]\\s*,\\s*'*\" + current.Name + \"'*\\[\"))\r\nand\r\nRowLevelSecurity.Any(it <> null)",
"CompatibilityLevel": 1200
},
{
"ID": "RELATIONSHIP_COLUMNS_SAME_DATA_TYPE",
"Name": "[エラー防止] リレーションシップで使用される列は同じデータ型を設定すること",
"Category": "エラー防止",
"Description": "リレーションシップで使用される列は、同じデータ型にすべきであり、理想的には、整数データ型にしておくことです。リレーションシップ内に異なるデータ型の列があると、さまざまな問題が発生する可能性があります。\n※関連規則の「[フォーマット]リレーションシップ用の列は整数型を使用する」を参照",
"Severity": 3,
"Scope": "Relationship",
"Expression": "FromColumn.DataType != ToColumn.DataType",
"CompatibilityLevel": 1200
},
{
"ID": "UNNECESSARY_COLUMNS",
"Name": "[メンテナンス]不要な列を削除する",
"Category": "メンテナンス",
"Description": "DAX式、リレーションシップ、階層レベル、「列で並び替え」で参照されていない非表示列は削除しておくべきです",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "(IsHidden or Table.IsHidden)\n\n\r\nand ReferencedBy.Count = 0\r\n\n\nand (not UsedInRelationships.Any())\n\n\r\nand (not UsedInSortBy.Any())\n\n\r\nand (not UsedInHierarchies.Any())\n\n\r\nand (not Table.RowLevelSecurity.Any(\nit <> null and it.IndexOf(\"[\" + current.Name + \"]\", \"OrdinalIgnoreCase\") >= 0\n))\n\n and (not Model.Roles.Any(RowLevelSecurity.Any(\nit <> null and \n(\nit.IndexOf(current.Table.Name + \"[\" + current.Name + \"]\", \"OrdinalIgnoreCase\") >= 0 or\n it.IndexOf(\"'\" + current.Table.Name + \"'[\" + current.Name + \"]\", \"OrdinalIgnoreCase\") >= 0\n )\n)))",
"FixExpression": "Delete()",
"CompatibilityLevel": 1200
},
{
"ID": "UNNECESSARY_MEASURES",
"Name": "[メンテナンス]不要なメジャーを削除",
"Category": "メンテナンス",
"Description": "DAX式で参照されていない非表示メジャーは、メンテナンスの観点から削除しておくべきです",
"Severity": 2,
"Scope": "Measure",
"Expression": "(Table.IsHidden or IsHidden) \r\nand ReferencedBy.Count = 0",
"FixExpression": "Delete()",
"CompatibilityLevel": 1200
},
{
"ID": "FIX_REFERENTIAL_INTEGRITY_VIOLATIONS",
"Name": "[メンテナンス]参照整合性の違反を修正",
"Category": "メンテナンス",
"Description": "このルールは、参照整合性に違反するリレーションシップを強調表示しています。これは、リレーションシップの 'from' 側のテーブルmany側に、リレーションシップの 'to' 側のテーブルone側に存在しない値があることを示します。参照整合性の違反は、スライサーで '空白' のメンバ値も生成します。これらの問題を解決するには、'to' テーブルの主キー列one側が 'from' テーブルの外部キー列many側のすべての値を持っていることを確認することが推奨されます。 参考: https://blog.enterprisedna.co/vertipaq-analyzer-tutorial-relationships-referential-integrity/",
"Severity": 2,
"Scope": "Relationship",
"Expression": "Convert.ToInt64(GetAnnotation(\"Vertipaq_RIViolationInvalidRows\")) > 0",
"CompatibilityLevel": 1200
},
{
"ID": "REMOVE_DATA_SOURCES_NOT_REFERENCED_BY_ANY_PARTITIONS",
"Name": "[メンテナンス]どのパーティションからも参照されていないデータソースを削除する",
"Category": "メンテナンス",
"Description": "どのパーティションからも参照されていないデータソースは削除しても良い",
"Severity": 1,
"Scope": "ProviderDataSource, StructuredDataSource",
"Expression": "UsedByPartitions.Count() == 0",
"FixExpression": "Delete()",
"CompatibilityLevel": 1200
},
{
"ID": "REMOVE_ROLES_WITH_NO_MEMBERS",
"Name": "[メンテナンス]メンバーのいないロールを削除する",
"Category": "メンテナンス",
"Description": "メンバーのいないロールを削除しても良い",
"Severity": 1,
"Scope": "ModelRole",
"Expression": "Members.Count() == 0",
"FixExpression": "Delete()",
"CompatibilityLevel": 1200
},
{
"ID": "ENSURE_TABLES_HAVE_RELATIONSHIPS",
"Name": "[メンテナンス]テーブルにリレーションシップがあることを確認",
"Category": "メンテナンス",
"Description": "このルールでは、データモデル内の他のテーブルにリレーションシップで接続されていないテーブルDisconnected Tablesがハイライトされます",
"Severity": 1,
"Scope": "Table, CalculatedTable",
"Expression": "UsedInRelationships.Count() == 0",
"CompatibilityLevel": 1200
},
{
"ID": "OBJECTS_WITH_NO_DESCRIPTION",
"Name": "[メンテナンス]説明なき表示されたオブジェクト",
"Category": "メンテナンス",
"Description": "オブジェクトテーブルに説明を追加します。これらの説明は、Power BI Desktopのフィールドリスト内でカーソルを置くと表示されます。さらに、これらの説明文を活用して、自動化されたデータ辞書を作成することができます下記リンク参照。\n参考 https://www.elegantbi.com/post/datadictionary",
"Severity": 1,
"Scope": "Table, Measure, DataColumn, CalculatedColumn, CalculatedTable, CalculatedTableColumn, CalculationGroup",
"Expression": "string.IsNullOrWhitespace(Description)\r\nand\r\nIsHidden == false",
"CompatibilityLevel": 1200
},
{
"ID": "PERSPECTIVES_WITH_NO_OBJECTS",
"Name": "[メンテナンス]オブジェクトのないパースペクティブ",
"Category": "メンテナンス",
"Description": "オブジェクト(テーブル)を含まないパースペクティブは、ほとんどの場合必要ありません。このルールでは、列/メジャー/階層をパースペクティブに追加すると、テーブルもパースペクティブに追加されるため、テーブルのみを確認する必要があります。さらに、一般的なテーブルには、計算テーブルCalculated Tablesや計算グループCalculation Groupsも含まれます",
"Severity": 1,
"Scope": "Perspective",
"Expression": "Model.Tables.Any(InPerspective[current.Name]) == false",
"FixExpression": "Delete()",
"CompatibilityLevel": 1200
},
{
"ID": "CALCULATION_GROUPS_WITH_NO_CALCULATION_ITEMS",
"Name": "[メンテナンス]計算項目Calculation Itemsが入っていない計算グループCalculation Groups",
"Category": "メンテナンス",
"Description": "計算グループCalculation Groupsは、計算アイテムCalculation Itemsがないと機能しません",
"Severity": 2,
"Scope": "CalculationGroup",
"Expression": "CalculationItems.Count == 0",
"CompatibilityLevel": 1200
},
{
"ID": "PARTITION_NAME_SHOULD_MATCH_TABLE_NAME_FOR_SINGLE_PARTITION_TABLES",
"Name": "[命名規則]パーティション名は、単一パーティションテーブルのテーブル名と一致する必要がある",
"Category": "命名規則",
"Description": "1つのパーティションを持つテーブルは、テーブル名とパーティション名を一致させる必要があります。2つ以上のパーティションを持つテーブルは、それぞれのパーティション名がテーブル名で始まる必要があります",
"Severity": 1,
"Scope": "Table",
"Expression": "(Partitions.Count = 1 and Partitions[0].Name <> Name)",
"FixExpression": "Partitions[0].Name = it.Name",
"CompatibilityLevel": 1200
},
{
"ID": "SPECIAL_CHARS_IN_OBJECT_NAMES",
"Name": "[命名規則]オブジェクト名に特殊文字を含めてはいけない",
"Category": "命名規則",
"Description": "タブ、改行などを含んではいけません",
"Severity": 2,
"Scope": "Model, Table, Measure, Hierarchy, Perspective, Partition, DataColumn, CalculatedColumn, CalculatedTable, CalculatedTableColumn, CalculationGroup, CalculationItem",
"Expression": "Name.IndexOf(char(9)) > -1\r\nor\r\n\nName.IndexOf(char(10)) > -1 \r\nor\r\n\nName.IndexOf(char(13)) > -1",
"CompatibilityLevel": 1200
},
{
"ID": "FORMAT_FLAG_COLUMNS_AS_YES/NO_VALUE_STRINGS",
"Name": "[書式設定]フラグ列をYes / Noの文字列として書式設定する",
"Category": "書式設定",
"Description": "フラグは、0/1の整数値を使用するよりも読みやすいように、Yes/Noとして適切にフォーマットされなければなりません",
"Severity": 1,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "(\nName.StartsWith(\"Is\") and \nDataType = \"Int64\" and \nnot (IsHidden or Table.IsHidden)\n) \r\nor\r\n\n(\nName.EndsWith(\" Flag\") and \nDataType <> \"String\" and \nnot (IsHidden or Table.IsHidden)\n)",
"CompatibilityLevel": 1200
},
{
"ID": "OBJECTS_SHOULD_NOT_START_OR_END_WITH_A_SPACE",
"Name": "[書式設定]オブジェクトはスペースで開始または終了してはいけない",
"Category": "書式設定",
"Description": "オブジェクトはスペースで始まったり、終わったりしてはいけません",
"Severity": 3,
"Scope": "Model, Table, Measure, Hierarchy, Perspective, Partition, DataColumn, CalculatedColumn",
"Expression": "Name.StartsWith(\" \") or Name.EndsWith(\" \")",
"CompatibilityLevel": 1200
},
{
"ID": "DATECOLUMN_FORMATSTRING",
"Name": "[書式設定]「日付」列の書式設定文字列Format Stringを指定する",
"Category": "書式設定",
"Description": "DateTime型の列で、名前に \"Month \"を含むものは、\"yyyy/mm/dd\"としてフォーマットすること",
"Severity": 1,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "Name.IndexOf(\"Date\", \"OrdinalIgnoreCase\") >= 0 \r\nand \r\nDataType = \"DateTime\" \r\nand \r\nFormatString <> \"yyyy/mm/dd\"",
"FixExpression": "FormatString = \"yyyy/mm/dd\"",
"CompatibilityLevel": 1200
},
{
"ID": "MONTHCOLUMN_FORMATSTRING",
"Name": "[書式設定]「月」列の書式設定文字列Format Stringを指定する",
"Category": "書式設定",
"Description": "DateTime型の列で、名前に \"Month \"(もしくは月)を含むものは、\"yyyy-MM\"としてフォーマットすること",
"Severity": 1,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "Name.IndexOf(\"Month\", \"OrdinalIgnoreCase\") >= 0 and DataType = \"DateTime\" and FormatString <> \"MMMM yyyy\"",
"FixExpression": "FormatString = \"MMMM yyyy\"",
"CompatibilityLevel": 1200
},
{
"ID": "PROVIDE_FORMAT_STRING_FOR_MEASURES",
"Name": "[書式設定]メジャーの書式設定文字列Format Stringを指定する",
"Category": "書式設定",
"Description": "表示されている(=使用されているメジャーには、その書式設定文字列Format Stringプロパティを割り当てる必要があります",
"Severity": 3,
"Scope": "Measure",
"Expression": "not IsHidden \r\nand not Table.IsHidden \r\nand string.IsNullOrWhitespace(FormatString)",
"CompatibilityLevel": 1200
},
{
"ID": "NUMERIC_COLUMN_SUMMARIZE_BY",
"Name": "[書式設定]数値列を集約しない",
"Category": "書式設定",
"Description": "数値列整数型、固定小数点、浮動小数点は、Power BIで誤って合計されるのを防ぐために、SummarizeByプロパティを「None」に設定する必要があります代わりにメジャーを作成します",
"Severity": 3,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "(\r\nDataType = \"Int64\"\r\nor \r\nDataType=\"Decimal\" \r\nor \r\nDataType=\"Double\"\r\n)\n\r\nand \r\nSummarizeBy <> \"None\"\r\n\nand not (IsHidden or Table.IsHidden)",
"FixExpression": "SummarizeBy = AggregateFunction.None",
"CompatibilityLevel": 1200
},
{
"ID": "PERCENTAGE_FORMATTING",
"Name": "[書式設定]パーセンテージは、千単位の区切り記号と小数点以下1桁で書式設定する",
"Category": "書式設定",
"Severity": 2,
"Scope": "Measure",
"Expression": "FormatString.Contains(\"%\") and FormatString <> \"#,0.0%;-#,0.0%;#,0.0%\"",
"FixExpression": "FormatString = \"#,0.0%\\u003B-#,0.0%\\u003B#,0.0%\"",
"CompatibilityLevel": 1200,
"Description": ""
},
{
"ID": "INTEGER_FORMATTING",
"Name": "[書式設定]整数は小数点なし、千単位で書式設定する",
"Category": "書式設定",
"Severity": 2,
"Scope": "Measure",
"Expression": "not FormatString.Contains(\"$\") and not FormatString.Contains(\"%\") and not (FormatString = \"#,0\" or FormatString = \"#,0.0\")",
"FixExpression": "FormatString = \"#,0\"",
"CompatibilityLevel": 1200,
"Description": ""
},
{
"ID": "RELATIONSHIP_COLUMNS_SHOULD_BE_OF_INTEGER_DATA_TYPE",
"Name": "[書式設定]リレーションシップ用の列は整数型を使用する",
"Category": "書式設定",
"Description": "リレーションシップの列は整数のデータ型であることがベスト・プラクティスです。これは、データウェアハウスだけでなく、データモデリングにも当てはまります",
"Severity": 1,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "UsedInRelationships.Any()\n\nand \n\nDataType != DataType.Int64",
"CompatibilityLevel": 1200
},
{
"ID": "ADD_DATA_CATEGORY_FOR_COLUMNS",
"Name": "[書式設定]列のデータ分類を追加",
"Category": "書式設定",
"Description": "適切に列へデータカテゴリのプロパティを追加する\n参考 https://docs.microsoft.com/power-bi/transform-model/desktop-data-categorization",
"Severity": 1,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "string.IsNullOrWhitespace(DataCategory)\r\nand\r\n(\r\n(\r\nName.ToLower().Contains(\"country\")\r\nor \r\n\nName.ToLower().Contains(\"continent\"\n)\r\nor\r\nName.ToLower().Contains(\"city\")\r\n)\r\nand DataType == \"String\"\r\n)\r\nor \r\n(\r\n(\nName.ToLower() == \"latitude\" \n or \nName.ToLower() == \"longitude\")\r\nand (DataType == DataType.Decimal or DataType == DataType.Double)\r\n)",
"CompatibilityLevel": 1200
},
{
"ID": "HIDE_FOREIGN_KEYS",
"Name": "[書式設定]外部キーFKを非表示にする",
"Category": "書式設定",
"Description": "外部キーは常に非表示にします",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "UsedInRelationships.Any(FromColumn.Name == current.Name and FromCardinality == \"Many\")\n\r\nand\r\n\nIsHidden == false",
"FixExpression": "IsHidden = true",
"CompatibilityLevel": 1200
},
{
"ID": "MARK_PRIMARY_KEYS",
"Name": "[書式設定]主キーPKをマークする",
"Category": "書式設定",
"Description": "列のプロパティで、主キー列の「Key」プロパティを「True」に設定します。",
"Severity": 1,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "UsedInRelationships.Any(ToTable.Name == current.Table.Name and ToColumn.Name == current.Name and ToCardinality == \"One\")\r\n\nand\r\n\nIsKey == false\r\nand\r\ncurrent.Table.DataCategory != \"Time\"",
"FixExpression": "IsKey = true",
"CompatibilityLevel": 1200
},
{
"ID": "HIDE_FACT_TABLE_COLUMNS",
"Name": "[書式設定]ファクトテーブルの列を非表示にする",
"Category": "書式設定",
"Description": "メジャーで集計に使用されるファクト・テーブルの列は非表示にするのがベスト・プラクティスです",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "(\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)COUNT\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)COUNTBLANK\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)SUM\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)AVERAGE\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)VALUES\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)DISTINCT\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)DISTINCTCOUNT\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\n\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)MIN\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\n\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)MAX\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)COUNTA\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\n\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)AVERAGEA\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)MAXA\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n\nor\r\nReferencedBy.AllMeasures.Any(RegEx.IsMatch(Expression,\"(?i)MINA\\s*\\(\\s*\\'*\" + outerit.Table.Name + \"\\'*\\[\" + outerit.Name + \"\\]\\s*\\)\"))\r\n)\r\n\nand IsHidden == false\r\n\nand (DataType == \"Int64\" || DataType == \"Decimal\" || DataType == \"Double\")",
"FixExpression": "IsHidden = true",
"CompatibilityLevel": 1200
},
{
"ID": "FIRST_LETTER_OF_OBJECTS_MUST_BE_CAPITALIZED",
"Name": "[書式設定]英語の場合、オブジェクトの最初の文字は大文字にする",
"Category": "書式設定",
"Severity": 1,
"Scope": "Table, Measure, Hierarchy, CalculatedColumn, CalculatedTable, CalculatedTableColumn, CalculationGroup",
"Expression": "Name.Substring(0,1).ToUpper() != Name.Substring(0,1)",
"CompatibilityLevel": 1200,
"Description": ""
},
{
"ID": "MONTH_(AS_A_STRING)_MUST_BE_SORTED",
"Name": "[書式設定]文字列ベースの月は「列で並び替え」を行う",
"Category": "書式設定",
"Description": "このルールは、文字列であり、ソートされていない月列をハイライトしています。「列で並べ替え」をしなかった場合、英語ではアルファベット順April、August...にソートされます。このような列に対して、並び替え用の数字列で適切にソートされるようにしてください1月、2月、3月...",
"Severity": 2,
"Scope": "DataColumn, CalculatedColumn, CalculatedTableColumn",
"Expression": "Name.ToUpper().Contains(\"MONTH\")\r\nand\r\n! Name.ToUpper().Contains(\"MONTHS\") \r\nand \r\n\n\nDataType == DataType.String \r\nand \r\nSortByColumn == null",
"CompatibilityLevel": 1200
}
]