Finally, we are going to do some fun stuff here 🙂 I recently took a part in a October challenge for Power Query, you may find it here. We will not go through the content of that challenge yet, as there is still time to submit your files by the end of October. I will talk about it in details closer to the end of the month, but for today, I wanted to tackle a specific problem from this challenge.

Main problem of the challenge

As you may find out, the challenge isn’t that hard in its base problem. Complexity is added when author mentions to try make it immune to column changes. Specifically, he would like this solution to work on all current future columns, that might be added to the source table. For us it means, that whatever we do in Power Query, we must avoid calling specific columns by their names. Of course, we will talk about the solution for entire challenge in next article, but we will try to solve today the problem of fixing column data types in a dynamic way.

How it’s done with UI

Power Query allows us to complete many operations, without writing single line of code. Transforming column types is one of these operations. All we need to do is to select a column choose the data type. There is actually at least three ways of doing it using UI.

We could assign each column individually, like presented above, but we also could use an option to detect all column types at once. And Power Query does pretty good job here, in most of the cases.Even if you don’t write code in Power Query, I always highly recommend enabling Formula Bar, as it helps to get familiar with the code. Once we are done with assigning column types, we should see the following step code:
Table.TransformColumnTypes(
    Source,
    {
        {"Client ID#", type text},
        {"System 1 contact ID", type text},
        {"System 2 contact ID", type text},
        {"System 3 contact ID", type text},
        {"Name", type text},
        {"Email", type text},
        {"Phone number", type text},
        {"Deal ID#s", type text}
    }
),

I formatted the code so it’s easier to understand what we need to achieve. It’s also important to mention, that we didn’t have to write this code, it was automatically generated while using UI. First line is a function responsible for transforming column types. Second line is the first argument which this function needs, so the table to work on. In our case, we are referencing the Source step, where table is defined. Second argument is simply the list of transformations, that happen for each column. Each transformation is of a list type as well, we can see it because of the curly brackets surrounding each argument.

Since we know that this is the place where column names are mentioned, this is going to be the part of code that we must create in a dynamic way. Our end result must be a list of lists, containing pairs of Column name and type of the data, which we want to assign to that column. Let’s remove this step from Power Query and we will start over. First function we will call is Table.ColumnNames:

 

This function needs only one argument – a table containing the columns we want to list. Here again we are referencing the Source step, where the table is defined. As a result, you see the List structure, containing all the column names from our table. With this one function we are almost there. We must create a list of lists, so far, we have a list of values, but at least we managed to call out all the column names, without mentioning them in the code!

How to create a list of lists in this case? We must Transform our current list, to wrap each item with curly brackets “{}”. This will assign given item to the list. Let’s try and use the following function:

List.Transform(                 // Function we need to call to transform the list
    Table.ColumnNames(Source),  // We take our list with Column Names as an argument
    each {_}                    // Item of the list is represented by "_"
)

We get the following output:

As we can see, we converted our list of values to list of lists, containing column names. But we need to two elements in each list, a column name, which we already have, and data type. We can add second element to list we created with curly brackets like this:

List.Transform(                 // Function we need to call to transform the list
    Table.ColumnNames(Source),  // We take our list with Column Names as an argument
    each {_, type text}         // Item of the list is represented by "_"
)

What we did now was very simple, only “type text” was added as a second element to the list we create from each column name. How could we make a good use of it for any future case? We can turn it into a Custom Function:

(sourceTable as table) =>                   // Our function expects table to be passed as an argument
let 
    transformationList = List.Transform(    // Function to Transform list of column names
        Table.ColumnNames(sourceTable),     // List of columns names
        each {_, type text}                 // Combine column name with data type
    )
in
    transformationList                      // Return the result

Now, coming back to the first code snippet we have on the top, where we see function assigning data types to each column, we must replace 2nd argument by invoking our custom function. If my function is named “AssignDataTypes”, code step looks as follows:

Instead of having the list of lists, with transformations for ech column, we have our custom function, that calls the names dynamically.

What about other data types?

Well, this is a good question. We could approach it in two ways (probably more than two, but we will cover two of them only :)). First would be to try detecting columns by name pattern, and assign different data types to them, or we could assign some of them manually, and tweak our function to change the type only for the remaining columns. Second approach turned out to be a bit more complex, so I will describe in another article. Let’s have a look at first scenario, detecting columns by naming patterns.

This could be easily explained with the date columns, as we could expect to find column names that contain “Date”. In this case, we could do the following:

(sourceTable as table) =>                   
let 
    transformationList = List.Transform(    
        Table.ColumnNames(sourceTable),    
        each
            // 1. We take each column name represented by "_"
            // 2. Check if that name contains phrase "Date"
            // 3. Assign data type accordingly
            if Text.Contains(_, "Date") then {_, type date}
            else {_, type text}             
    )
in
    transformationList

Instead of assigning text type everywhere, as I added an “if” statement to find columns, that might contain “Date” in the name, and assign “type date” instead. The result is the following:

Last column has been correctly classified as Date column, and the rest we see appearing as Text columns.

Conclusion

We managed not only to build a solution, dynamically assigned column types in our table, but we even extended the functionality to assign different data types, based on name pattern detection. I hope you find this solution useful. If you have any questions, let me know in the comments section.

Thank you for reading, and till next time 🙂

Picture of Pawel Wrona

Pawel Wrona

Lead author and founder of the blog | Works as a Power BI Architect in global company | Passionate about Power BI and Microsoft Tech

Did you enjoy this article? Share with others :)

5 5 votes
Article Rating
Comments notifications
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Related Posts