Forum Discussion

robertpisarek's avatar
robertpisarek
Regular Visitor
8 years ago
Solved

Merge in Power Query based on conditions

How to merge the same table based on two conditions in PowerQuery?

 

For example in SQL:

 

select * from Table1 t1
inner join Table1 t2 on
t1.TransactionID = t2.TransactionID
and t1.CategoryID <> t2.CategoryID

  • My suggestion would be to join on TransactionID and remove the results where the CategoryID's are equal.
    As you require an inner join, this also means removing empty nested tables.

     

    let
        Source = Table.NestedJoin(Table1,{"TransactionID"},Table1,{"TransactionID"},"t2",JoinKind.Inner),
        FilteredOnCategory = Table.ReplaceValue(Source,each [t2],(Earlier) => Table.SelectRows(Earlier[t2],each [CategoryID] <> Earlier[CategoryID]), Replacer.ReplaceValue,{"t2"}),
        RestoredType = Value.ReplaceType(FilteredOnCategory,Value.Type(Source)),
        FilteredNoEmptyTables = Table.SelectRows(RestoredType, each not Table.IsEmpty([t2])),
        Expanded_t2 = Table.ExpandTableColumn(FilteredNoEmptyTables, "t2", {"CategoryID"}, {"t2.CategoryID"})
    in
        Expanded_t2

     

    The RestoredType step restores the column types from the Source table, as Table.ReplaceValues resets all column types to any.

5 Replies

  • MarcelBeug's avatar
    MarcelBeug
    Community Champion

    My suggestion would be to join on TransactionID and remove the results where the CategoryID's are equal.
    As you require an inner join, this also means removing empty nested tables.

     

    let
        Source = Table.NestedJoin(Table1,{"TransactionID"},Table1,{"TransactionID"},"t2",JoinKind.Inner),
        FilteredOnCategory = Table.ReplaceValue(Source,each [t2],(Earlier) => Table.SelectRows(Earlier[t2],each [CategoryID] <> Earlier[CategoryID]), Replacer.ReplaceValue,{"t2"}),
        RestoredType = Value.ReplaceType(FilteredOnCategory,Value.Type(Source)),
        FilteredNoEmptyTables = Table.SelectRows(RestoredType, each not Table.IsEmpty([t2])),
        Expanded_t2 = Table.ExpandTableColumn(FilteredNoEmptyTables, "t2", {"CategoryID"}, {"t2.CategoryID"})
    in
        Expanded_t2

     

    The RestoredType step restores the column types from the Source table, as Table.ReplaceValues resets all column types to any.

    • Anonymous's avatar
      Anonymous
      Not applicable

      Hello  MarcelBeug 

       

      I am trying to wrap my head around the function you created for the 3rd argument NewValue inside Table.ReplaceValue()

      Could you please explain how does this function work and especially the logic highlighted in red

       

       


      FilteredOnCategory
          = Table.ReplaceValue(// table, oldValue, NewValue, replacer as function, col to search. replace one value with another in the specified columns      Source,     each [t2], // oldValue                           (Earlier) => Table.SelectRows(Earlier[t2],each [CategoryID] <> Earlier[CategoryID]), // NewValue       Replacer.ReplaceValue,{"t2"} // Replacer "t2" field name  ),

        

      Thanks

      • MarcelBeug's avatar
        MarcelBeug
        Community Champion

        "Earlier" is just the name of a parameter, it may be anything (e.g. "This", "Each", "ThisRow", "Currentt"), but I chose "Earlier" like EARLIER in DAX.

         

        In fact "Earlier" is equivalent with the record that makes up each row in table Source.

        In Source, the column t2 consists of nested tables (the Table1 tables after the join with itself).

        In these nested tables, only the records must be selected with a Category different from the Category in Source.

        So the nested tables are represented by Earlier[t2] and the CategoryID inside these tables are represented by [CategoryID].

        The Source[CategoryID] is represented by Earlier[CategoryID].

         

        Earlier => is equivalent with each, but each cannot be used, as a qualifier is required to distinguish between the CategoryID in Source and the CategoryID inside the nested tables in t2.