Forum Discussion
How to apply List for Dynamics Column Names in subsequence steps
- 2 years ago
If it is only the last three columns that need to have dynamic names, you can set the data types for all the columns by creating a list similar to:
#"Types List" = {{"Region", type text}, {"Country", type text}, {"Item", type text}, {"Price", Currency.Type}, {"Color", type text}} & List.Transform(List.LastN(Table.ColumnNames(#"Promoted Headers"),3), each {_, Int64.Type}),Then you can use it in the Transform.ColumnTypes function like:
#"Promoted Headers" = ..., #"Types List" = {{"Region", type text}, {"Country", type text}, {"Item", type text}, {"Price", Currency.Type}, {"Color", type text}} & List.Transform(List.LastN(Table.ColumnNames(#"Promoted Headers"),3), each {_, Int64.Type}), #"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers", #"Types List") in #"Changed Type"
Hello! Here is a custom function you can use to detect the column types without specifying column names. Add a new blank query, go to the Advanced Editor and replace the contents with the custom function script below. Name the query fnDetectDataTypes. Then replace your Table.TransformColumnTypes step with this:
= fnDetectDataTypes(#"Promoted Headers")
Custom Function
// ****************************************************************************************************************/
// fnDetectDataTypes
// ****************************************************************************************************************/
// PURPOSE
// - Detect data types from a table's data and transform to the appropriate type
//
// LIMITATIONS
// -
//
// DEVELOPER (Adapted from)
// - https://www.thebiccountant.com/2020/05/01/detect-change-types-of-all-columns-in-power-query/
// ****************************************************************************************************************/
let
fn = (table as table, optional first_n_records as nullable number, optional culture as nullable text) as table =>
let
TextColumns = Table.ColumnsOfType ( table, {type nullable text} ),
TempKey = "--(^_^)--",
ReplaceNulls = Table.ReplaceValue ( table, null, TempKey, Replacer.ReplaceValue, TextColumns),
InvalidTypes = {type list, type record, type table, type function, type type, type null, type duration},
Culture = if culture = null then "en-US" else culture,
TopRows = if first_n_records = null then 200 else top_records, //set default to 200 rows to establish a column type
TopNRows = Table.FirstN(ReplaceNulls, TopRows),
ColumnNameList = Table.ColumnNames(TopNRows),
ColumnDataLists = List.Accumulate(ColumnNameList, {}, (accumulated, i) => accumulated & {Table.Column(TopNRows, i)}),
ColumnTypes = List.Transform(ColumnDataLists, (i) => List.ItemType(i)),
TransformList = List.Select(List.Zip({ColumnNameList, ColumnTypes}), (i) => not List.Contains(List.Transform(InvalidTypes, (j) => Type.Is(i{1}, j)), true)),
TypedTable = Table.TransformColumnTypes(ReplaceNulls, TransformList, Culture),
List.ItemType = (list as list) =>
let
ItemTypes = List.Transform(
list,
each
if Value.Type(Value.FromText(_, Culture)) = type number
then
if Text.Contains(Text.From(_, Culture),"%")
then Percentage.Type
else
if Text.Length(Text.Remove(Text.From(_, Culture), {"0".."9"} & Text.ToList("., -+eE()/'"))) > 0
then Currency.Type
else
if Int64.From(_, Culture) = Value.FromText(_, Culture)
then Int64.Type
else type number
else Value.Type(Value.FromText(_, Culture))
),
ListItemType = Type.Union(ItemTypes)
in
ListItemType
in
let
//RemoveInvalidTypes = Table.RemoveColumns ( TypedTable, Table.ColumnsOfType ( TypedTable, {type list, type record, type table, type function} ) ),
// dataflows currently converts all dates to datetime
PrimitiveTypes = Table.ColumnsOfType(TypedTable, {type nullable number, type nullable text, type nullable logical, type nullable datetime}),
NonConformingTypes = List.RemoveMatchingItems ( Table.ColumnNames ( TypedTable ), PrimitiveTypes ),
NonConformingTypesToText = Table.TransformColumnTypes( TypedTable, List.Zip( { NonConformingTypes,
List.Repeat( {type text}, List.Count( NonConformingTypes ) ) } ) ),
TextColumnsNew = Table.ColumnsOfType (NonConformingTypesToText, {type nullable text} ),
ReplaceTempKey = Table.ReplaceValue(NonConformingTypesToText ,TempKey,"",Replacer.ReplaceValue, TextColumnsNew )
in
ReplaceTempKey
in
fn
- M0012 years agoHelper I
Hi Jenn,
My question is more about why the column names for 2024, 2025 and 2026 that I have converted to a List (named as Year) doesnt work when I put in the following code. Thank you
= Table.TransformColumnTypes(#"Promoted Headers",{{Year, Int64.Type}})- jennratten2 years agoSuper User
If your 'Year' field contains a list of values, like this:
and your objective it to simply set the correct type for the column, it would not be 'Int64.Type' because your field does not contain integers - it contains a list of integers. Therefore, you would leave it as 'type any' by omitting it from the transform column types step.