This note explains how to turn the current views (wide–from–tall) into a report‑friendly table using Power Query (recommended) or DAX. It covers two common layouts:
- Attribute-only column headers
META_TYPE+ATTRIBUTEas prefixed column headers
It also shows how to extract a human‑readable Description from the JSON in VALUE_METADATA.
Source schema (tall, meta-driven)
Expected columns:
OBJECT_SEQMETA_TYPEATTRIBUTECODE_VALUEVALUE_METADATA(JSON)CREATE_DATEEXPIRY_DATESOURCE_SYSTEMACTIVE_FLAGCHECKSUM
Assumption: Each
(OBJECT_SEQ, [META_TYPE], ATTRIBUTE)appears at most once for the snapshot you are pivoting. If you have duplicates (e.g. overlapping validity), filter first (e.g.ACTIVE_FLAG = 1, or latestCREATE_DATE).
Pivot Pattern A — Attribute‑only headers
Goal: One row per OBJECT_SEQ, one column per ATTRIBUTE, with the cell value = CODE_VALUE.
Steps (Power Query)
- Start with your table in Power Query (Transform Data).
- Remove unneeded columns:
VALUE_METADATA,CREATE_DATE,EXPIRY_DATE,SOURCE_SYSTEM,ACTIVE_FLAG,CHECKSUM.
- Ensure key columns present: keep
OBJECT_SEQ,ATTRIBUTE,CODE_VALUE(and optionallyMETA_TYPEif needed for later checks). - Pivot: Transform ➜ Pivot Column
- Column to pivot:
ATTRIBUTE - Values column:
CODE_VALUE - Advanced options ➜ Aggregate value function: Don’t Aggregate.
- Column to pivot:
- Result: a wide table with one column per attribute.
Notes
- If Power Query forces an aggregation, you have duplicate
(OBJECT_SEQ, ATTRIBUTE)rows. Resolve by filtering to one row per pair.
Pivot Pattern B — META_TYPE prefix + ATTRIBUTE
Goal: Use META_TYPE as a prefix so headers look like TYPE_ATTRIBUTE (e.g. EMP_Name).
Steps (Power Query)
- Add a new column that combines
META_TYPEandATTRIBUTEusing theText.Combine()function:- Add Column ➜ Custom Column
- Name:
ATTR_KEY - Formula (M):
Text.Combine({[META_TYPE], [ATTRIBUTE]}, "_")
Text.Combine()automatically ignores nulls, so you won’t get stray underscores whenMETA_TYPEis blank or null. - (Optional) Remove the original
META_TYPEcolumn after creatingATTR_KEY. - Remove unneeded columns as in Pattern A.
- Pivot:
- Column to pivot:
ATTR_KEY - Values column:
CODE_VALUE - Aggregate: Don’t Aggregate.
- Column to pivot:
Adding a human‑readable Description
If you want a Description alongside or instead of CODE_VALUE, many attributes include JSON in VALUE_METADATA, typically with fields like CODE and DESC.
Steps (Power Query)
- Keep
VALUE_METADATAfor this step. - Parse JSON: select
VALUE_METADATA➜ Transform ➜ Parse ➜ JSON. The column becomes Record values. - Expand the record: click the expand icon and select the fields you need (usually
CODE,DESC). You’ll get new columns, e.g.VALUE_METADATA.CODE,VALUE_METADATA.DESC. - Create a final description column that uses
DESCwhen available, otherwise falls back toCODE(orCODE_VALUE):- Add Column ➜ Custom Column
- Name:
VALUE_DESC - Formula (M):
let d = [VALUE_METADATA.DESC], c = [VALUE_METADATA.CODE] in if d <> null and d <> "" then d else if c <> null and c <> "" then c else [CODE_VALUE]
- Clean up: remove intermediary columns you no longer need (e.g.
VALUE_METADATA,VALUE_METADATA.CODE,VALUE_METADATA.DESC). - Pivot on
ATTRIBUTE(Pattern A) orATTR_KEY(Pattern B) usingVALUE_DESCas the Values column (and Don’t Aggregate).
Optional: Doing it in DAX instead of Power Query
Power Query is typically simpler for this pattern. If you must pivot in DAX (e.g. to keep the tall table and compute a wide view), create calculated columns or measures:
- Prefixed header key (calculated column):
ATTR_KEY = COALESCE([META_TYPE] & "_", "") & [ATTRIBUTE] - Wide table via summarise + pivot (pattern):
Wide = VAR T = SELECTCOLUMNS('Tall', "OBJECT_SEQ", 'Tall'[OBJECT_SEQ], "ATTR_KEY", COALESCE('Tall'[META_TYPE] & "_", "") & 'Tall'[ATTRIBUTE], "VAL", 'Tall'[CODE_VALUE] ) RETURN SUMMARIZECOLUMNS( 'Tall'[OBJECT_SEQ], // One column per attribute key // Replace ATTR1, ATTR2 with actual attribute keys from your data model "ATTR1", CALCULATE(SELECTEDVALUE(T[VAL])), "ATTR2", CALCULATE(SELECTEDVALUE(T[VAL])) )This is more manual and brittle than Power Query. Prefer Power Query where possible.
End‑to‑end example (Power Query M)
Below is a compact M script you can adapt. It implements Pattern B with Description extraction and falls back to CODE_VALUE when JSON is missing.
let
Source = YourSourceHere,
KeepCols = Table.SelectColumns(Source, {"OBJECT_SEQ","META_TYPE","ATTRIBUTE","CODE_VALUE","VALUE_METADATA","ACTIVE_FLAG","CREATE_DATE"}, MissingField.Ignore),
AddKey = Table.AddColumn(KeepCols, "ATTR_KEY", each Text.Combine({[META_TYPE], [ATTRIBUTE]}, "_"), type text),
ParseJSON = Table.TransformColumns(AddKey, {{"VALUE_METADATA", each try Json.Document(_) otherwise null}}),
ExpandJSON = Table.ExpandRecordColumn(ParseJSON, "VALUE_METADATA", {"CODE","DESC"}, {"META_CODE","META_DESC"}),
AddDesc = Table.AddColumn(ExpandJSON, "VALUE_DESC", each let d=[META_DESC], c=[META_CODE] in if d <> null and d <> "" then d else if c <> null and c <> "" then c else [CODE_VALUE], type text),
Trim = Table.SelectColumns(AddDesc, {"OBJECT_SEQ","ATTR_KEY","ATTRIBUTE","CODE_VALUE","VALUE_DESC"}),
ValuesColumn = "CODE_VALUE", // or switch to "VALUE_DESC"
Pivoted = Table.Pivot(Trim, List.Distinct(Trim[ATTR_KEY]), "ATTR_KEY", ValuesColumn)
in
Pivoted
Don’t Aggregate in the UI corresponds to
Table.Pivotwithout an aggregation function in M. If you see an aggregation function (e.g.List.Sum), you have duplicates — fix upstream.
Quality & performance tips
- De‑duplicate before pivot to guarantee one row per
(OBJECT_SEQ, header key). - Filter to current rows if your source contains history. Typical filters:
ACTIVE_FLAG = 1, orEXPIRY_DATEis null / in the future, or- keep the latest
CREATE_DATEper key.
- Column data types: set
CODE_VALUE/VALUE_DESCto Text before pivot to avoid unintended numeric aggregation. - Column naming hygiene: prefer
TYPE_ATTRwithout spaces to simplify DAX. - Downstream joins: keep
OBJECT_SEQas the key to join to your fact/dimension tables.
Quick checklist
- Removed:
VALUE_METADATA,CREATE_DATE,EXPIRY_DATE,SOURCE_SYSTEM,ACTIVE_FLAG,CHECKSUM(unless needed for filtering). - Built header key:
ATTRIBUTEorMETA_TYPE+_+ATTRIBUTE. - JSON parsed and
VALUE_DESCcreated (optional). - Pivoted on header key with Don’t Aggregate and Values =
CODE_VALUEorVALUE_DESC. - Duplicates resolved prior to pivot.
- Data types set correctly.
FAQ
Q: Is there a COALESCE() in Power Query?
A: No. Use Text.Combine() instead, which naturally ignores nulls. COALESCE() does exist in DAX.
Q: Why am I forced to aggregate in the pivot dialog?
A: You have duplicate (OBJECT_SEQ, HeaderKey) rows. Filter to a single current row per key before pivoting.
Q: Where do I get descriptions?
A: From VALUE_METADATA JSON → expand to CODE/DESC → build VALUE_DESC with fallbacks → pivot using VALUE_DESC if desired.