<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ahmed Essam</title>
    <description>The latest articles on Forem by Ahmed Essam (@essam404).</description>
    <link>https://forem.com/essam404</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3573086%2F84f8bbda-962a-4854-8593-b75a5a2ad9b1.jpg</url>
      <title>Forem: Ahmed Essam</title>
      <link>https://forem.com/essam404</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/essam404"/>
    <language>en</language>
    <item>
      <title>Bulletproof Power Query (Part 2): A Smart, Fuzzy-Match Rename Function</title>
      <dc:creator>Ahmed Essam</dc:creator>
      <pubDate>Thu, 18 Dec 2025 07:31:35 +0000</pubDate>
      <link>https://forem.com/essam404/bulletproof-power-query-part-2-a-smart-fuzzy-match-rename-function-4n6c</link>
      <guid>https://forem.com/essam404/bulletproof-power-query-part-2-a-smart-fuzzy-match-rename-function-4n6c</guid>
      <description>&lt;p&gt;In &lt;strong&gt;&lt;a href="https://dev.to/essam404/supercharge-your-power-query-transformations-a-flexible-function-for-changing-column-types-4e4e"&gt;Part 1 of this series&lt;/a&gt;&lt;/strong&gt;, we tackled the fragile &lt;code&gt;ChangeType&lt;/code&gt; step and built a function to handle data conversion errors gracefully.&lt;/p&gt;

&lt;p&gt;But what happens &lt;em&gt;before&lt;/em&gt; you change types? What if the column name itself changes?&lt;/p&gt;

&lt;p&gt;We have all been there. You build a perfect Power BI report or Excel dashboard. It runs smoothly for weeks. Then, one day, the refresh fails. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Error:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Expression.Error: The column 'Total Sales' of the table wasn't found.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Cause:&lt;/strong&gt;&lt;br&gt;
The source system updated a column header from &lt;code&gt;Total Sales&lt;/code&gt; to &lt;code&gt;total_sales&lt;/code&gt; (case/format change) or &lt;code&gt;Total Sale&lt;/code&gt; (typo).&lt;/p&gt;

&lt;p&gt;Standard Power Query functions are &lt;strong&gt;rigid&lt;/strong&gt;. They demand exact matches. However, in the real world, data is rarely that clean. You need a function that "thinks" like a human.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution: &lt;code&gt;Table.RenameColumnsSmart&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;I have developed a robust replacement for the standard rename function. Instead of blindly looking for an exact text match, this function uses a &lt;strong&gt;3-tier search logic&lt;/strong&gt; to find your columns, ensuring your query survives dirty data updates.&lt;/p&gt;
&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Exact Match:&lt;/strong&gt; Checks if the column exists exactly as requested.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Normalization:&lt;/strong&gt; Ignores case, underscores, and extra spaces (e.g., &lt;code&gt;Cust ID&lt;/code&gt; will match &lt;code&gt;cust_id&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Fuzzy Matching:&lt;/strong&gt; Uses the &lt;strong&gt;Jaccard Similarity&lt;/strong&gt; algorithm. If you ask for &lt;code&gt;Revenue&lt;/code&gt; but the source has &lt;code&gt;Revenu&lt;/code&gt; (typo), it calculates the similarity score. If it's high enough (e.g., &amp;gt;80%), it accepts the match automatically.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The "Professional" Touch: Metadata Logging
&lt;/h3&gt;

&lt;p&gt;Just like in Part 1, we don't want to fail silently. If a column is truly missing (e.g., the similarity score is too low), this function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Does NOT break the query.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Logs the warning&lt;/strong&gt; to the table's &lt;code&gt;Metadata&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This allows your data to keep flowing while giving you a hidden audit trail to check for quality issues.&lt;/p&gt;
&lt;h2&gt;
  
  
  The M Code
&lt;/h2&gt;

&lt;p&gt;Copy and paste the code below into a &lt;strong&gt;Blank Query&lt;/strong&gt; in Power Query and name it &lt;code&gt;fxSmartRename&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    Table.RenameColumnsSmart = (
        SourceTable as table, 
        Renames as list, 
        optional SimilarityThreshold as number
    ) as table =&amp;gt;
    let
        /* CONFIGURATION 
           Default threshold is 0.8 (80% similarity) if not provided.
           1.0 = Exact match required.
           0.0 = Matches anything (Dangerous).
        */
        Threshold = if SimilarityThreshold = null then 0.8 else SimilarityThreshold,

        // 1. Helper: Clean text for comparison (Lower case, remove spaces/punctuation)
        CleanText = (t as text) =&amp;gt; 
            Text.Lower(Text.Select(t, {"a".."z", "0".."9", "A".."Z"})),

        // 2. Helper: Calculate Jaccard Similarity between two strings
        GetSimilarity = (txt1 as text, txt2 as text) as number =&amp;gt;
            let
                l1 = Text.ToList(CleanText(txt1)),
                l2 = Text.ToList(CleanText(txt2)),
                Intersect = List.Count(List.Intersect({l1, l2})),
                Union = List.Count(List.Distinct(List.Combine({l1, l2}))),
                Score = if Union = 0 then 0 else Intersect / Union
            in
                Score,

        // Get actual column names from the source table
        ActualColumns = Table.ColumnNames(SourceTable),

        /* PROCESS RENAMES
           Iterate through the user's requested renames. 
           Try to find the best match in the actual table.
        */
        ProcessedRenames = List.Transform(Renames, (item) =&amp;gt; 
            let
                TargetName = item{0},
                NewName = item{1},

                // Tier 1: Try Exact Match
                ExactMatch = List.Contains(ActualColumns, TargetName),

                // Tier 2: Try Cleaned Match (Case Insensitive + Ignore Space)
                CleanedMatch = if ExactMatch then TargetName else 
                    List.First(List.Select(ActualColumns, each CleanText(_) = CleanText(TargetName))),

                // Tier 3: Try Fuzzy Match (Similarity Score)
                BestMatch = if CleanedMatch &amp;lt;&amp;gt; null then CleanedMatch else
                    let
                        Scored = List.Transform(ActualColumns, each {_, GetSimilarity(TargetName, _)}),
                        Sorted = List.Sort(Scored, {each _{1}, Order.Descending}),
                        TopResult = List.First(Sorted),
                        IsGoodMatch = TopResult{1} &amp;gt;= Threshold
                    in
                        if IsGoodMatch then TopResult{0} else null
            in
                // Return a record with details on what happened
                [
                    Requested = TargetName, 
                    NewName = NewName, 
                    FoundMatch = BestMatch, 
                    Status = if BestMatch &amp;lt;&amp;gt; null then "Renamed" else "Missing"
                ]
        ),

        // Filter down to the list of successful renames for the native function
        ValidRenamesList = List.Transform(
            List.Select(ProcessedRenames, each [Status] = "Renamed"), 
            each {[FoundMatch], [NewName]}
        ),

        // Create a list of warnings (Missing columns)
        MissingColumns = List.Transform(
            List.Select(ProcessedRenames, each [Status] = "Missing"), 
            each [Requested]
        ),

        // Apply the standard RenameColumns function using our smart list
        // MissingField.Ignore is used as a safety net.
        RenamedTable = Table.RenameColumns(SourceTable, ValidRenamesList, MissingField.Ignore),

        // Attach the missing column warnings to the Table's Metadata.
        TableWithMeta = Value.ReplaceType(
            RenamedTable, 
            Value.Type(RenamedTable) meta [
                SmartRename_Warnings = MissingColumns, 
                SmartRename_Log = ProcessedRenames
            ]
        )
    in
        TableWithMeta
in
    Table.RenameColumnsSmart

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage Example
&lt;/h2&gt;

&lt;p&gt;Imagine your source data is messy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected: Employee ID, Annual Salary&lt;/li&gt;
&lt;li&gt;Actual Data: emp_id, Anual Salary (Note the typo in Salary)
Here is how you call the function:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Apply the Smart Rename
CleanData = fxSmartRename(
    SourceTable, 
    {
        {"Employee ID", "ID"},      // Finds 'emp_id' via normalization
        {"Annual Salary", "Salary"} // Finds 'Anual Salary' via Fuzzy Match
    }, 
    0.8 // Sensitivity (80% match required)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;emp_id&lt;/code&gt; is successfully renamed to &lt;strong&gt;ID&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Anual Salary&lt;/code&gt; is successfully renamed to &lt;strong&gt;Salary&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The query &lt;strong&gt;does not break&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Checking for Warnings
&lt;/h2&gt;

&lt;p&gt;If you want to see if any columns were missed (and therefore skipped), you can check the metadata of your result step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Add a custom step to view warnings
CheckWarnings = Value.Metadata(CleanData)[SmartRename_Warnings]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By combining the Smart Type Change from Part 1 and this Smart Rename from Part 2, you now have a "Self-Healing" ETL foundation. These functions allow you to build Power BI reports and Excel tools that are resilient to the chaos of real-world data.&lt;/p&gt;

&lt;p&gt;Stay tuned for more robust M patterns!&lt;/p&gt;

</description>
      <category>powerquery</category>
      <category>powerbi</category>
      <category>dataengineering</category>
      <category>excel</category>
    </item>
    <item>
      <title>Supercharge Your Power Query Transformations: A Flexible Function for Changing Column Types</title>
      <dc:creator>Ahmed Essam</dc:creator>
      <pubDate>Sat, 18 Oct 2025 22:12:08 +0000</pubDate>
      <link>https://forem.com/essam404/supercharge-your-power-query-transformations-a-flexible-function-for-changing-column-types-4e4e</link>
      <guid>https://forem.com/essam404/supercharge-your-power-query-transformations-a-flexible-function-for-changing-column-types-4e4e</guid>
      <description>&lt;p&gt;Power Query is an incredibly powerful tool for data wrangling, but anyone who has worked with real-world, messy data knows the frustration of a query that breaks because of a simple type conversion error. The built-in &lt;code&gt;Table.TransformColumnTypes&lt;/code&gt; function is great, but it can be rigid. What happens if a column is unexpectedly missing? Or if some rows contain text in a column you want to convert to a number? Your entire refresh fails.&lt;/p&gt;

&lt;p&gt;To solve this, I've developed a powerful, flexible, and robust custom function in Power Query M called &lt;code&gt;fnTransformColumnTypes&lt;/code&gt;. This function not only does everything the standard function does but also gives you complete control over how to handle common data cleaning challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Wrong with the Default?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dl1nrskz30cl9csqqm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1dl1nrskz30cl9csqqm1.png" alt="Old Table.TransformColumnTypes" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The standard &lt;code&gt;Table.TransformColumnTypes&lt;/code&gt; is all-or-nothing. It fails under two very common conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Missing Columns:&lt;/strong&gt; If you tell it to transform a column that doesn't exist in the source data (perhaps the name was changed upstream), the query throws an error and stops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversion Errors:&lt;/strong&gt; If you're converting a column to a number and it contains a text value like &lt;code&gt;"N/A"&lt;/code&gt;, the query also fails.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our custom function gracefully handles both of these scenarios and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing &lt;code&gt;fnTransformColumnTypes&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This function is a drop-in replacement that adds a layer of intelligence and flexibility to your data transformations. At its core, it allows you to define how it should behave when things don't go as planned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Handle Missing Columns:&lt;/strong&gt; You decide what happens when a column isn't found.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"Error"&lt;/code&gt; (Default): Behaves like the standard function and stops with an error.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"Ignore"&lt;/code&gt;: Simply skips the transformation for the missing column and moves on.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"Null"&lt;/code&gt;: Adds the missing column to your table and fills it with &lt;code&gt;null&lt;/code&gt; values, ensuring your downstream steps don't break.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Manage Conversion Errors:&lt;/strong&gt; You can choose whether to let conversion errors stop your query or automatically convert them to &lt;code&gt;null&lt;/code&gt; values.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Culture-Specific Formatting:&lt;/strong&gt; Just like the standard function, you can specify a culture code (e.g., &lt;code&gt;"en-US"&lt;/code&gt;, &lt;code&gt;"de-DE"&lt;/code&gt;) to correctly interpret numbers and dates.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;p&gt;First, create a new blank query in Power Query and paste in the following code. You can then rename the query to &lt;code&gt;fnTransformColumnTypes&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    // Define the final, flexible function
    ChangeTypesFunction = (
        sourceTable as table, 
        typeTransformations as list, 
        optional MissingColumnAction as nullable text, 
        optional HandleConversionErrors as nullable logical, 
        optional Culture as nullable text
    ) as table =&amp;gt;
        let
            // --- 1. Set Final Parameter Values with Defaults ---
            // If optional parameters are not provided, these lines assign their default values.
            finalMissingColumnAction = if MissingColumnAction = null then "Error" else MissingColumnAction,
            finalHandleConversionErrors = if HandleConversionErrors = null then false else HandleConversionErrors,
            finalCulture = Culture, // Defaults to null if not provided

            // --- 1.1. Validate Parameter Values ---
            // This step validates the values for specific parameters, like 'MissingColumnAction'.
            _valueValidation = let
                    allowedActions = {"Ignore", "Error", "Null"},
                    providedAction = finalMissingColumnAction
                in
                    if not List.Contains(allowedActions, providedAction) then
                        error "Invalid value for 'MissingColumnAction'. Provided value was '" &amp;amp; providedAction &amp;amp; "'. Allowed values are: 'Ignore', 'Error', 'Null'."
                    else
                        null, // Value is valid

            // --- 1.2. Evaluation Gate ---
            // This dummy variable forces Power Query to evaluate the validation step above.
            // Because of lazy evaluation, without this, the error check would never be triggered.
            _gate = _valueValidation,

            // --- 2. Identify and Categorize Columns ---
            // Get the list of column names that actually exist in the source table.
            sourceColumns = Table.ColumnNames(sourceTable),
            // Extract just the names of all columns the user requested to transform.
            requestedColumns = List.Transform(typeTransformations, each _{0}),
            // Filter the user's list to include only transformations for columns that exist in the source table.
            validTransformations = List.Select(typeTransformations, each List.Contains(sourceColumns, _{0})),
            // Get the names of the valid columns.
            validColumnNames = List.Transform(validTransformations, each _{0}),
            // Identify the names of requested columns that were NOT found in the source table.
            ignoredColumns = List.RemoveItems(requestedColumns, validColumnNames),
            // Get the full transformation details (name and type) for the missing columns.
            // This is needed for the 'AddAsNullColumn' action to set the correct data type.
            ignoredTransformations = List.Select(typeTransformations, each not List.Contains(sourceColumns, _{0})),

            // --- 3. Perform Initial Type Transformations on Existing Columns ---
            // Apply the type changes to the columns that were found in the source table.
            tableWithPotentialErrors = Table.TransformColumnTypes(sourceTable, validTransformations, finalCulture),
            // Check the configuration to see if we should handle conversion errors.
            transformedTable = if finalHandleConversionErrors = true then
                // If so, replace any errors from the transformation step with null values.
                Table.ReplaceErrorValues(tableWithPotentialErrors, List.Transform(validTransformations, each {_{0}, null}))
            else
                // Otherwise, leave the errors as they are.
                tableWithPotentialErrors,

            // --- 4. Handle Missing Columns Based on the Chosen Action ---
            // Decide the final output based on whether columns were missing and the 'MissingColumnAction' configuration.
            outputTable =
                if List.IsEmpty(ignoredColumns) then
                    // CASE 1: No columns were missing, so no special action is needed.
                    // Simply return the table with transformations applied to the existing columns.
                    transformedTable
                else
                    // CASE 2: One or more requested columns were not found in the source table.
                    // The action taken is determined by the 'MissingColumnAction' option.
                    if finalMissingColumnAction = "Null" then
                        // ACTION 2A: Add each missing column to the table with its specified type and null values.
                        List.Accumulate(
                            ignoredTransformations,
                            transformedTable,
                            (currentTable, columnTransformation) =&amp;gt; Table.AddColumn(currentTable, columnTransformation{0}, each null, columnTransformation{1})
                        )
                    else if finalMissingColumnAction = "Ignore" then
                        // ACTION 2B: Do nothing with the missing columns and return the table as is.
                        transformedTable
                    else 
                        // ACTION 2C (DEFAULT): This covers the "Error" case. Throw an informative error and stop execution.
                        error "The following columns were not found: " &amp;amp; Text.Combine(ignoredColumns, ", ")
        in
            outputTable,

    // --- Documentation &amp;amp; Metadata ---
    // This metadata provides information about the function in the Power Query UI.
    Documentation = [
        Documentation.Name = "fnTransformColumnTypes",
        Documentation.Description = "Changes the data type of specified columns. Provides configurable actions for handling columns that are not found in the source table and for managing data conversion errors.",
        Documentation.Author = "AHMED ESSAM",
        Documentation.Examples = {[
            Description = "Transforms the 'Sales' column to a number and the 'OrderDate' column to a date. A missing 'Region' column will be added and filled with nulls.",
            Code = "let
    Source = Table.FromRecords({
        [ID = 1, Sales = ""100.5"", OrderDate = ""2023-01-15""],
        [ID = 2, Sales = ""-50"", OrderDate = ""2023-01-16""],
        [ID = 3, Sales = ""Invalid"", OrderDate = ""2023-01-17""]
    }),
    Transformations = {
        {""Sales"", type number},
        {""OrderDate"", type date},
        {""Region"", type text}
    }
in
    fnTransformColumnTypes(
        Source, 
        Transformations, 
        ""Null"", 
        true, 
        ""en-US""
    )",
            Result = "/* Resulting table will have:
- 'Sales' column as numeric (with the 'Invalid' entry as null).
- 'OrderDate' column as date type.
- A new 'Region' column of type text, filled with nulls.
*/"
        ]}
    ]
in
    // Attach the function to its metadata to make the documentation visible.
    Value.ReplaceType(ChangeTypesFunction, Value.ReplaceMetadata(Value.Type(ChangeTypesFunction), Documentation))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Function Signature
&lt;/h3&gt;

&lt;p&gt;You can then call this function in any other query like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fnTransformColumnTypes(
    sourceTable as table,
    typeTransformations as list,
    optional MissingColumnAction as text,
    optional HandleConversionErrors as logical,
    optional Culture as text
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical Example
&lt;/h2&gt;

&lt;p&gt;Let's say you have the following source table with some messy data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Sales&lt;/th&gt;
&lt;th&gt;OrderDate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;100.5&lt;/td&gt;
&lt;td&gt;2023-01-15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;-50&lt;/td&gt;
&lt;td&gt;2023-01-16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Invalid&lt;/td&gt;
&lt;td&gt;2023-01-17&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You want to perform the following transformations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Convert &lt;code&gt;Sales&lt;/code&gt; to a &lt;code&gt;number&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert &lt;code&gt;OrderDate&lt;/code&gt; to a &lt;code&gt;date&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Convert a &lt;code&gt;Region&lt;/code&gt; column to &lt;code&gt;text&lt;/code&gt; (note: this column doesn't exist!).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's how you'd call the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    Source = Table.FromRecords({
        [ID = 1, Sales = "100.5", OrderDate = "2023-01-15"],
        [ID = 2, Sales = "-50", OrderDate = "2023-01-16"],
        [ID = 3, Sales = "Invalid", OrderDate = "2023-01-17"]
    }),

    // Define the list of transformations
    Transformations = {
        {"Sales", type number},
        {"OrderDate", type date},
        {"Region", type text}
    },

    // Invoke the function
    Result = fnTransformColumnTypes(
        Source,
        Transformations,
        "Null", // Add missing columns as null
        true,   // Handle conversion errors
        "en-US" // Specify culture
    )
in
    Result

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;p&gt;The function will produce the following clean, transformed table without any errors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Sales&lt;/th&gt;
&lt;th&gt;OrderDate&lt;/th&gt;
&lt;th&gt;Region&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;100.5&lt;/td&gt;
&lt;td&gt;2023-01-15&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;-50&lt;/td&gt;
&lt;td&gt;2023-01-16&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;2023-01-17&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdjf06i22tzlb42px9xi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdjf06i22tzlb42px9xi.png" alt="New fnTransformColumnTypes" width="706" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the &lt;code&gt;"Invalid"&lt;/code&gt; sales value became &lt;code&gt;null&lt;/code&gt;, and the missing &lt;code&gt;Region&lt;/code&gt; column was added and filled with &lt;code&gt;nulls&lt;/code&gt;. Your query refresh is now resilient to these common data issues!&lt;/p&gt;

&lt;p&gt;By adding this single function to your Power Query toolkit, you can save hours of debugging and build more reliable and robust data models.&lt;/p&gt;

&lt;p&gt;Happy querying! 🚀&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>microsoft</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
