Starting December 3, join live sessions with database experts and the Microsoft product team to learn just how easy it is to get started
Learn moreGet certified in Microsoft Fabric—for free! For a limited time, get a free DP-600 exam voucher to use by the end of 2024. Register now
I'd like to know how to properly restore type information for several columns after they got lost as result of a "type destructive" step in a query.
I'm thinking of transferring type information for multiple (or all) columns to a table from another one (which would be, in my case, an "undamaged" earlier copy of the same table, with still intact type information).
This makes use of Table.ReplaceValue (this is the, as I understand it, more "modern" approach, at least I learned about it much later then the second approach below). When updating values in a column based on data from other columns, the target column has the "any" type after that operation.
Example:
let
Source = Table.PromoteHeaders(Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs7PMVTSAVFGEMpYKVYnOq80J0dHKREokoTgJgO5KQhuKpCbhuCmA7kZSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)))),
Types = Table.TransformColumnTypes(Source, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}}),
Updates = Table.ReplaceValue(Types, each [Col1], each [Col2] & [Col3], Replacer.ReplaceValue, {"Col1"}),
RestoreTypes = Table.TransformColumnTypes(Updates, {{"Col1", type text}})
in
RestoreTypes
As you see, the column "Col1" has no specific type any more after the Table.ReplaceValue step and I need to explicitly restore it in the last step. As this affects only individual columns (the ones I actually update), that would still be manageable.
But I also have lots of documents which use the older approach with nested Table.FromRecords, Table.TransformRows and Record.TransformFields.
Example:
let
Source = Table.PromoteHeaders(Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs7PMVTSAVFGEMpYKVYnOq80J0dHKREokoTgJgO5KQhuKpCbhuCmA7kZSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)))),
Types = Table.TransformColumnTypes(Source, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}}),
Updates = Table.FromRecords(Table.TransformRows(Types, (r) => Record.TransformFields(r, {{"Col1", each r[Col2] & r[Col3]}}))),
RestoreTypes = Table.TransformColumnTypes(Updates, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}})
in
RestoreTypes
Due to the deconstruction of the table into individual rows (records), which are then transformed and afterwards reassembled into a table, the type information is lost here for all columns, whether they are "target columns" (actually modified/updated) or just "source columns" (used to update other columns).
I then need to restore the type information for all columns at once, which is tedious and ugly if it affects several columns and/or needs to be done repeatedly.
I though an elegant way to deal with the problem would be to save the type information prior to such updates steps and restoring it later (knowing that my update operations do not change the type). But I don't know how to do that.
I know there's Table.Schema. My idea was something like this:
Table = …, (the original table with type information on all columns)
Schema = Table.Schema(Table),
TransformationList = List.Zip(Schema[Name], ‹list of types›), ← I'm struggling here
UpdatedTable = …, (some code that updates Table)
TableWithTypesAgain = List.TransformColumnTypes(UpdatedTable, TransformationList)
Basically saving the type information of a table and restoring it later. But how to build that ‹list of types› used above? How to get a proper list of types e.g. from the Schema[TypeName] or Schema[Kind] columns?
Thanks a lot for your input!
Solved! Go to Solution.
Hi, you can restore types directly in Table.FromRecords. Add this as 2nd argument. (This works also with other functions - not only with Table.FromRecords.)
If you want to add new column and specify type directly - you can do this trick:
let
Source = Table.PromoteHeaders(Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs7PMVTSAVFGEMpYKVYnOq80J0dHKREokoTgJgO5KQhuKpCbhuCmA7kZSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)))),
Types = Table.TransformColumnTypes(Source, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}}),
AddedNewColumnRestoreTypes = Table.FromColumns(Table.ToColumns(Types) & {{1,2,3,4}}, Value.Type(Types & #table(type table[New Column = Int64.Type], {})))
in
AddedNewColumnRestoreTypes
If you want to restore types after replacing value - you can do this:
let
Source = Table.PromoteHeaders(Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs7PMVTSAVFGEMpYKVYnOq80J0dHKREokoTgJgO5KQhuKpCbhuCmA7kZSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)))),
Types = Table.TransformColumnTypes(Source, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}}),
ReplaceValue = Table.ReplaceValue(Types, null, null, (x,y,z)=> if x <> "a" then x else "x", {"Col2"}),
RestoreTypes = Value.ReplaceType(ReplaceValue, Value.Type(Types))
in
RestoreTypes
Hi, you can restore types directly in Table.FromRecords. Add this as 2nd argument. (This works also with other functions - not only with Table.FromRecords.)
If you want to add new column and specify type directly - you can do this trick:
let
Source = Table.PromoteHeaders(Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs7PMVTSAVFGEMpYKVYnOq80J0dHKREokoTgJgO5KQhuKpCbhuCmA7kZSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)))),
Types = Table.TransformColumnTypes(Source, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}}),
AddedNewColumnRestoreTypes = Table.FromColumns(Table.ToColumns(Types) & {{1,2,3,4}}, Value.Type(Types & #table(type table[New Column = Int64.Type], {})))
in
AddedNewColumnRestoreTypes
If you want to restore types after replacing value - you can do this:
let
Source = Table.PromoteHeaders(Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs7PMVTSAVFGEMpYKVYnOq80J0dHKREokoTgJgO5KQhuKpCbhuCmA7kZSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)))),
Types = Table.TransformColumnTypes(Source, {{"Col1", type text}, {"Col2", type text}, {"Col3", type text}}),
ReplaceValue = Table.ReplaceValue(Types, null, null, (x,y,z)=> if x <> "a" then x else "x", {"Col2"}),
RestoreTypes = Value.ReplaceType(ReplaceValue, Value.Type(Types))
in
RestoreTypes
That's so great, thanks a lot! 👏
I looked over the "type functions" section in the help (Power Qery M formula language), but didn't have the idea to go through the "value functions" list.
Your hints solved my problems, both Value.Type and Value.ReplaceType are invaluable – no idea how I could work without them for so long 😀. I theoretically knew about the option to add a type information as second parameter of many functions, but I'm not using it often enough I guess.
I learned a lot, much appreciated!
Starting December 3, join live sessions with database experts and the Fabric product team to learn just how easy it is to get started.
March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount! Early Bird pricing ends December 9th.
User | Count |
---|---|
24 | |
13 | |
12 | |
11 | |
8 |
User | Count |
---|---|
42 | |
25 | |
14 | |
14 | |
12 |