Skip to content

Commit 1ff1127

Browse files
Fix to support composite key columns (GroupByColumns) in StatExtractor. (#159)
This update resolves an issue in StatExtractor where an error occurred during the extraction of relationship statistics when one of the columns in the relationship was part of a composite key (GroupByColumns). The error message was: "Column [] is part of composite key, but not all columns of the composite key are included in the expression or its dependent expression." This fix applies only to models with a compatibility level of 1200 or higher, as GroupByColumns is not available in levels 1100 and 1103.
1 parent 6122894 commit 1ff1127

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

src/Dax.Model.Extractor/StatExtractor.cs

+45-9
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ private void LoadRelationshipStatistics(int sampleRows = 0,bool analyzeDirectQue
9191
CALCULATETABLE (
9292
ROW(
9393
""RelationshipId"", {rel.Dmv1200RelationshipId},
94-
""MissingKeys"", DISTINCTCOUNT ( {EscapeColumnName(rel.FromColumn)} ),
94+
""MissingKeys"", {DistinctCountExpression(rel.FromColumn)},
9595
""InvalidRows"", COUNTROWS({EscapeTableName(rel.FromColumn.Table)})
9696
),
97-
ISBLANK( {EscapeColumnName(rel.ToColumn)} ),
97+
{IsBlankExpression(rel.ToColumn)},
9898
USERELATIONSHIP( {EscapeColumnName(rel.FromColumn)}, {EscapeColumnName(rel.ToColumn)} )
9999
)").ToArray());
100100
// ""Column"", ""{EmbedNameInString(rel.FromColumn.ColumnName.Name)}"",
@@ -138,11 +138,11 @@ private void LoadRelationshipStatistics(int sampleRows = 0,bool analyzeDirectQue
138138
relationshipSet.Select(rel => (rel.MissingKeys > sampleRows && rel.MissingKeys <= MAX_KEYS_FOR_SAMPLE) ?
139139
$@"CALCULATETABLE (
140140
SELECTCOLUMNS (
141-
SAMPLE ( {sampleRows}, DISTINCT ( {EscapeColumnName(rel.FromColumn)} ), {EscapeColumnName(rel.FromColumn)}, ASC ),
141+
SAMPLE ( {sampleRows}, {DistinctExpression(rel.FromColumn)}, {EscapeColumnName(rel.FromColumn)}, ASC ),
142142
""RelationshipId"", {rel.Dmv1200RelationshipId},
143143
""MissingValue"", {EscapeColumnName(rel.FromColumn)}
144144
),
145-
ISBLANK( {EscapeColumnName(rel.ToColumn)} ),
145+
{IsBlankExpression(rel.ToColumn)},
146146
USERELATIONSHIP( {EscapeColumnName(rel.FromColumn)}, {EscapeColumnName(rel.ToColumn)} )
147147
)"
148148
: (DaxModel.CompatibilityLevel >= 1200) ?
@@ -155,7 +155,7 @@ private void LoadRelationshipStatistics(int sampleRows = 0,bool analyzeDirectQue
155155
""RelationshipId"", {rel.Dmv1200RelationshipId},
156156
""MissingValue"", {EscapeColumnName(rel.FromColumn)}
157157
))),
158-
ISBLANK( {EscapeColumnName(rel.ToColumn)} ),
158+
{IsBlankExpression(rel.ToColumn)},
159159
USERELATIONSHIP( {EscapeColumnName(rel.FromColumn)}, {EscapeColumnName(rel.ToColumn)} )
160160
)"
161161
:
@@ -237,15 +237,51 @@ private static string EscapeTableName(Table table)
237237

238238
private static string DistinctCountExpression(Column column)
239239
{
240-
// We always use COUNTROWS(ALLNOBLANKROW(t[c])) instead of DISTINCTCOUNT(t[c]) because it is compatible with GroupByColumns settings, such as Fields Parameters.
241-
// COUNTROWS(ALLNOBLANKROW()) always reads the list of values from the attribute hierarchy (when AvailableInMDX=true) or queries the table if the hierarchy is not available (when AvailableInMDX=false)
240+
var columnName = EscapeColumnName(column);
241+
242+
if (column.GroupByColumns.Count == 0) {
243+
return $"DISTINCTCOUNT({columnName})";
244+
}
245+
else {
246+
// COUNTROWS(ALLNOBLANKROW(t[c])) is compatible with GroupByColumns settings like Fields Parameters because it always retrieves the list of
247+
// values from the attribute hierarchy (when AvailableInMDX=true), or queries the table if the hierarchy is unavailable (AvailableInMDX=false).
248+
return $"COUNTROWS(ALLNOBLANKROW({columnName}))";
249+
}
250+
}
251+
252+
private static string DistinctExpression(Column column)
253+
{
254+
var columnName = EscapeColumnName(column);
242255

243-
return $"COUNTROWS(ALLNOBLANKROW({EscapeColumnName(column)}))";
256+
if (column.GroupByColumns.Count == 0) {
257+
return $"DISTINCT({columnName})";
258+
}
259+
else {
260+
var groupingColumnNames = string.Join(", ", column.GroupByColumns.Select((cn) => EscapeColumnName(column.Table, cn)));
261+
var tableName = EscapeTableName(column.Table);
262+
return $"DISTINCT(SELECTCOLUMNS(SUMMARIZE({tableName}, {columnName}, {groupingColumnNames}), {columnName}))";
263+
}
244264
}
245265

266+
private static string IsBlankExpression(Column column)
267+
{
268+
var columnName = EscapeColumnName(column);
269+
270+
if (column.GroupByColumns.Count == 0) {
271+
return $"ISBLANK({columnName})";
272+
}
273+
else {
274+
var groupingColumnNames = string.Join(", ", column.GroupByColumns.Select((cn) => EscapeColumnName(column.Table, cn)));
275+
return $"FILTER(ALL({columnName}, {groupingColumnNames}), ISBLANK({columnName}))";
276+
}
277+
}
246278
private static string EscapeColumnName(Column column)
247279
{
248-
return $"{EscapeTableName(column.Table)}[{column.ColumnName.Name.Replace("]", "]]")}]";
280+
return EscapeColumnName(column.Table, column.ColumnName);
281+
}
282+
private static string EscapeColumnName(Table table, DaxName columnName)
283+
{
284+
return $"{EscapeTableName(table)}[{columnName.Name.Replace("]", "]]")}]";
249285
}
250286
private static string EmbedNameInString(string originalName)
251287
{

0 commit comments

Comments
 (0)