6

I ran into a problem with Power Query (M Language) Table.Join() function. Just to demonstrate the issue, I am altering the example taken from the Table.Join Documentation Page.

See the JoinKind.LeftOuter hint at the end

= Table.Join(
    Table.FromRecords({
        [CustomerID = 1, Name = "Bob", Phone = "123-4567"],
        [CustomerID = 2, Name = "Jim", Phone = "987-6543"],
        [CustomerID = 3, Name = "Paul", Phone = "543-7890"],
        [CustomerID = 4, Name = "Ringo", Phone = "232-1550"]
    }),
    "CustomerID",
    Table.FromRecords({
        [OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
        [OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
        [OrderID = 3, CustomerID = 2, Item = "Fishing net", Price = 25.0],
        [OrderID = 4, CustomerID = 3, Item = "Fish tazer", Price = 200.0],
        [OrderID = 5, CustomerID = 3, Item = "Bandaids", Price = 2.0],
        [OrderID = 6, CustomerID = 1, Item = "Tackle box", Price = 20.0],
        [OrderID = 7, CustomerID = 5, Item = "Bait", Price = 3.25]
    }),
    "CustomerID", JoinKind.LeftOuter

)

Without this hint the the function is running well. With the hint it is failing because of the duplicate column name.

Expression.Error: A join operation cannot result in a table with duplicate column names ("CustomerID").
Details:
    [Type]

From my perspective this is a bug, the key cannot be a duplicate.

I run into this issue, because the two tables I am trying to join share the same column names besides the join key. Is there a trick how to alias them similarly to a SQL?

3 Answers 3

4

Variant 1

Is there a trick how to alias them similarly to a SQL

Yes, there is, Table.PrefixColumns:

Table.Join(
    Table.FromRecords({
        [CustomerID = 1, Name = "Bob", Phone = "123-4567"],
        [CustomerID = 2, Name = "Jim", Phone = "987-6543"],
        [CustomerID = 3, Name = "Paul", Phone = "543-7890"],
        [CustomerID = 4, Name = "Ringo", Phone = "232-1550"]
    }),
    "CustomerID",
    Table.PrefixColumns(Table.FromRecords({
        [OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
        [OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
        [OrderID = 3, CustomerID = 2, Item = "Fishing net", Price = 25.0],
        [OrderID = 4, CustomerID = 3, Item = "Fish tazer", Price = 200.0],
        [OrderID = 5, CustomerID = 3, Item = "Bandaids", Price = 2.0],
        [OrderID = 6, CustomerID = 1, Item = "Tackle box", Price = 20.0],
        [OrderID = 7, CustomerID = 5, Item = "Bait", Price = 3.25]
    }), "Orders"),
    "Orders.CustomerID", JoinKind.LeftOuter
)

Variant 2

Improved version of @Alexis Olson's answer.

Even inner join allows equal column names for keys only. All other columns have to have unique names. If your data schema is not stable you can find that errors happen here and there, regardless of join kind. Nested join, proposed by Alexis, is good. But you still have to list column names. That's +1 place to change.

If you code by hand (not using GUI much), there is better approach — convert tables to lists of records:

let
    Customers =
        Table.FromRecords({
            [CustomerID = 1, Name = "Bob", Phone = "123-4567"],
            [CustomerID = 2, Name = "Jim", Phone = "987-6543"],
            [CustomerID = 3, Name = "Paul", Phone = "543-7890"],
            [CustomerID = 4, Name = "Ringo", Phone = "232-1550"]
        }),
    Orders =
        Table.FromRecords({
            [OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
            [OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
            [OrderID = 3, CustomerID = 2, Item = "Fishing net", Price = 25.0],
            [OrderID = 4, CustomerID = 3, Item = "Fish tazer", Price = 200.0],
            [OrderID = 5, CustomerID = 3, Item = "Bandaids", Price = 2.0],
            [OrderID = 6, CustomerID = 1, Item = "Tackle box", Price = 20.0],
            [OrderID = 7, CustomerID = 5, Item = "Bait", Price = 3.25]
        }),
    LeftJoin =
        Table.NestedJoin(
            Customers, "CustomerID",
            Orders, "CustomerID",
            "Orders", JoinKind.LeftOuter
        ),
    TransformToList =
        Table.TransformColumns(
            LeftJoin,
            { { "Orders", each Table.ToRecords(_) } }
        ),
    #"Expanded Orders" =
        Table.ExpandListColumn(
            TransformToList, "Orders"
        )
in
    #"Expanded Orders"

All fields remain accessible, for example:

        Table.AddColumn(
            #"Expanded Orders",
            "Something for fishing?",
            each [Orders] <> null and Text.Contains([Orders][Item], "fish", Comparer.OrdinalIgnoreCase),
            type logical
        )

But of course such nested record fields can't be used for keys or another join. And they are not directly observable with GUI.

Sign up to request clarification or add additional context in comments.

Comments

2

This works fine if it's an inner join but with a left outer join, this leads to duplicate column names because CustomerID from the first table and CustomerID from the second table are different. You could rename one of the columns as a workaround. For example, this does work:

let
    Table1 = Table.Join(
    Table.FromRecords({
        [ID = 1, Name = "Bob", Phone = "123-4567"],
        [ID = 2, Name = "Jim", Phone = "987-6543"],
        [ID = 3, Name = "Paul", Phone = "543-7890"],
        [ID = 4, Name = "Ringo", Phone = "232-1550"]
    }),
    "ID",
    Table.FromRecords({
        [OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
        [OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
        [OrderID = 3, CustomerID = 2, Item = "Fishing net", Price = 25.0],
        [OrderID = 4, CustomerID = 3, Item = "Fish tazer", Price = 200.0],
        [OrderID = 5, CustomerID = 3, Item = "Bandaids", Price = 2.0],
        [OrderID = 6, CustomerID = 1, Item = "Tackle box", Price = 20.0],
        [OrderID = 7, CustomerID = 5, Item = "Bait", Price = 3.25]
    }),
    "CustomerID", JoinKind.LeftOuter

)
in
    Table1

If you don't want to do the renaming workaround mentioned in that link, you can use Table.NestedJoin and Table.Expand like the GUI would generate.

let
    Customers =
        Table.FromRecords({
            [CustomerID = 1, Name = "Bob", Phone = "123-4567"],
            [CustomerID = 2, Name = "Jim", Phone = "987-6543"],
            [CustomerID = 3, Name = "Paul", Phone = "543-7890"],
            [CustomerID = 4, Name = "Ringo", Phone = "232-1550"]
        }),
    Orders =
        Table.FromRecords({
            [OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
            [OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
            [OrderID = 3, CustomerID = 2, Item = "Fishing net", Price = 25.0],
            [OrderID = 4, CustomerID = 3, Item = "Fish tazer", Price = 200.0],
            [OrderID = 5, CustomerID = 3, Item = "Bandaids", Price = 2.0],
            [OrderID = 6, CustomerID = 1, Item = "Tackle box", Price = 20.0],
            [OrderID = 7, CustomerID = 5, Item = "Bait", Price = 3.25]
        }),
    LeftJoin =
        Table.NestedJoin
            Customers, "CustomerID",
            Orders, "CustomerID",
            "Orders", JoinKind.LeftOuter
        ),
    #"Expanded Orders" =
        Table.ExpandTableColumn(
            LeftJoin, "Orders",
            {"OrderID", "Item", "Price"}, {"OrderID", "Item", "Price"}
        )
in
    #"Expanded Orders"

1 Comment

I was reading the link you posted, and it seems that he run into the same issue. Ok so not a bug, just inconsistent behavior.
0

This seems to work fine for me Main differences seems to be NestedJoin instead of Table.Join

= Table.NestedJoin(Table.FromRecords({
    [CustomerID = 1, Name = "Bob", Phone = "123-4567"],
    [CustomerID = 2, Name = "Jim", Phone = "987-6543"],
    [CustomerID = 3, Name = "Paul", Phone = "543-7890"],
    [CustomerID = 4, Name = "Ringo", Phone = "232-1550"]
}),
{"CustomerID"},
Table.FromRecords({
    [OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
    [OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
    [OrderID = 3, CustomerID = 2, Item = "Fishing net", Price = 25.0],
    [OrderID = 4, CustomerID = 3, Item = "Fish tazer", Price = 200.0],
    [OrderID = 5, CustomerID = 3, Item = "Bandaids", Price = 2.0],
    [OrderID = 6, CustomerID = 1, Item = "Tackle box", Price = 20.0],
    [OrderID = 7, CustomerID = 5, Item = "Bait", Price = 3.25]
}),
{"CustomerID"},"xx",JoinKind.LeftOuter)

1 Comment

NestedJoin function is another similar function, the problem I do have is with Join function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.