|
| 1 | +# Advanced Analysis Examples using pbix2vpax() |
| 2 | + |
| 3 | +## Comparing Model Versions |
| 4 | + |
| 5 | +**Track changes between model versions:** |
| 6 | +```sql |
| 7 | +WITH |
| 8 | +current_version AS ( |
| 9 | + SELECT pbix2vpax('Sales_Model_v2.pbix') as analysis |
| 10 | +), |
| 11 | +previous_version AS ( |
| 12 | + SELECT pbix2vpax('Sales_Model_v1.pbix') as analysis |
| 13 | +), |
| 14 | +current_measures AS ( |
| 15 | + SELECT |
| 16 | + meas.MeasureName, |
| 17 | + meas.TableName, |
| 18 | + meas.MeasureExpression, |
| 19 | + meas.DataType |
| 20 | + FROM (SELECT UNNEST((SELECT analysis FROM current_version).Measures) as meas) |
| 21 | +), |
| 22 | +previous_measures AS ( |
| 23 | + SELECT |
| 24 | + meas.MeasureName, |
| 25 | + meas.TableName, |
| 26 | + meas.MeasureExpression, |
| 27 | + meas.DataType |
| 28 | + FROM (SELECT UNNEST((SELECT analysis FROM previous_version).Measures) as meas) |
| 29 | +), |
| 30 | +current_tables AS ( |
| 31 | + SELECT |
| 32 | + tab.TableName, |
| 33 | + tab.RowsCount, |
| 34 | + tab.TableSize, |
| 35 | + part.RefreshedTime |
| 36 | + FROM (SELECT UNNEST((SELECT analysis FROM current_version).Tables) as tab), |
| 37 | + (SELECT UNNEST((SELECT analysis FROM current_version).Partitions) as part) |
| 38 | + WHERE tab.TableName = part.TableName |
| 39 | +), |
| 40 | +previous_tables AS ( |
| 41 | + SELECT |
| 42 | + tab.TableName, |
| 43 | + tab.RowsCount, |
| 44 | + tab.TableSize, |
| 45 | + part.RefreshedTime |
| 46 | + FROM (SELECT UNNEST((SELECT analysis FROM previous_version).Tables) as tab), |
| 47 | + (SELECT UNNEST((SELECT analysis FROM previous_version).Partitions) as part) |
| 48 | + WHERE tab.TableName = part.TableName |
| 49 | +) |
| 50 | +SELECT |
| 51 | + 'Measure Changes' as ChangeType, |
| 52 | + c.MeasureName as Name, |
| 53 | + c.TableName, |
| 54 | + CASE |
| 55 | + WHEN p.MeasureName IS NULL THEN 'Added' |
| 56 | + WHEN c.MeasureExpression != p.MeasureExpression THEN 'Modified' |
| 57 | + ELSE 'Unchanged' |
| 58 | + END as Status, |
| 59 | + c.MeasureExpression as CurrentDefinition, |
| 60 | + p.MeasureExpression as PreviousDefinition |
| 61 | +FROM current_measures c |
| 62 | +LEFT JOIN previous_measures p ON c.MeasureName = p.MeasureName AND c.TableName = p.TableName |
| 63 | +WHERE p.MeasureName IS NULL OR c.MeasureExpression != p.MeasureExpression |
| 64 | + |
| 65 | +UNION ALL |
| 66 | + |
| 67 | +SELECT |
| 68 | + 'Table Size Changes' as ChangeType, |
| 69 | + c.TableName as Name, |
| 70 | + NULL as TableName, |
| 71 | + 'Modified' as Status, |
| 72 | + CONCAT( |
| 73 | + 'Rows: ', c.RowsCount, ' (', |
| 74 | + CASE WHEN c.RowsCount > p.RowsCount THEN '+' ELSE '' END, |
| 75 | + c.RowsCount - p.RowsCount, ') | ', |
| 76 | + 'Size: ', ROUND(c.TableSize / 1024.0 / 1024.0, 2), 'MB (', |
| 77 | + CASE WHEN c.TableSize > p.TableSize THEN '+' ELSE '' END, |
| 78 | + ROUND((c.TableSize - p.TableSize) / 1024.0 / 1024.0, 2), 'MB) | ', |
| 79 | + 'Last Refresh: ', c.RefreshedTime |
| 80 | + ) as CurrentDefinition, |
| 81 | + CONCAT( |
| 82 | + 'Rows: ', p.RowsCount, ' | ', |
| 83 | + 'Size: ', ROUND(p.TableSize / 1024.0 / 1024.0, 2), 'MB | ', |
| 84 | + 'Last Refresh: ', p.RefreshedTime |
| 85 | + ) as PreviousDefinition |
| 86 | +FROM current_tables c |
| 87 | +INNER JOIN previous_tables p ON c.TableName = p.TableName |
| 88 | +WHERE c.RowsCount != p.RowsCount OR ABS(c.TableSize - p.TableSize) > 1024 |
| 89 | +ORDER BY ChangeType, Status DESC, Name; |
| 90 | +``` |
| 91 | + |
| 92 | +## Batch Analysis Across Multiple Files |
| 93 | + |
| 94 | +**Search for DAX functions across all models:** |
| 95 | +```sql |
| 96 | +WITH model_measures AS ( |
| 97 | + SELECT |
| 98 | + file, |
| 99 | + UNNEST(pbix2vpax(file).Measures) as meas |
| 100 | + FROM (SELECT unnest(glob('data/reports/**/*.pbix')) as file) |
| 101 | +) |
| 102 | +SELECT |
| 103 | + file, |
| 104 | + meas.TableName, |
| 105 | + meas.MeasureName, |
| 106 | + meas.MeasureExpression, |
| 107 | + CASE |
| 108 | + WHEN meas.MeasureExpression ILIKE '%USERELATIONSHIP%' THEN 'USERELATIONSHIP' |
| 109 | + WHEN meas.MeasureExpression ILIKE '%CALCULATE%' THEN 'CALCULATE' |
| 110 | + WHEN meas.MeasureExpression ILIKE '%TREATAS%' THEN 'TREATAS' |
| 111 | + WHEN meas.MeasureExpression ILIKE '%CROSSFILTER%' THEN 'CROSSFILTER' |
| 112 | + END as DAXFunction |
| 113 | +FROM model_measures |
| 114 | +WHERE meas.MeasureExpression ILIKE '%USERELATIONSHIP%' |
| 115 | + OR meas.MeasureExpression ILIKE '%TREATAS%' |
| 116 | + OR meas.MeasureExpression ILIKE '%CROSSFILTER%' |
| 117 | +ORDER BY DAXFunction, file, meas.MeasureName; |
| 118 | +``` |
| 119 | + |
| 120 | +**Find models with specific table structures:** |
| 121 | +```sql |
| 122 | +-- Find all models that have a 'Date' table with specific columns |
| 123 | +WITH model_columns AS ( |
| 124 | + SELECT |
| 125 | + REGEXP_EXTRACT(file, '([^/]+)\.pbix$', 1) as ModelName, |
| 126 | + file, |
| 127 | + col.TableName, |
| 128 | + col.ColumnName, |
| 129 | + col.DataType |
| 130 | + FROM (SELECT unnest(glob('data/reports/**/*.pbix')) as file), |
| 131 | + LATERAL (SELECT UNNEST(pbix2vpax(file).Columns) as col) |
| 132 | + WHERE col.TableName = 'Date' |
| 133 | +) |
| 134 | +SELECT |
| 135 | + ModelName, |
| 136 | + file, |
| 137 | + STRING_AGG(ColumnName, ', ' ORDER BY ColumnName) as DateColumns, |
| 138 | + COUNT(*) as ColumnCount |
| 139 | +FROM model_columns |
| 140 | +GROUP BY ModelName, file |
| 141 | +HAVING COUNT(*) >= 5 -- Models with at least 5 date columns |
| 142 | +ORDER BY ColumnCount DESC; |
| 143 | +``` |
0 commit comments