Power Query has a lot of built in functions, but it doesn’t have a function that exactly matches the VLOOKUP in Excel – but by using the M language and other M functions we can certainly replicate some of the VLOOKUP functionality and make an even more flexible lookup function.
Now the example data is like this
In Excel we would lookup the price for at specific productkey by using this formula
– in this case ProductKey 1 with a price of 100.
In order to replicate this in Power Query we can use the function List.PositionOf
So I add a new blank query
And then use the function List.PositionOf – with the following arguments
List – Is the column ProductKey from my lookuptable Products – refer to like this Products[ProductKey]
Value – Is the value to look in this case the value 1
Occurrence – Is set to 0 to only return one value
This will return the position of the value in the list – sort of like using the MATCH function in Excel
Now to return the price – we can use this result to lookup the price like this
= Products[Price]{List.PositionOf(Products[ProductKey], 1, 0)}
And we get 100 returned which is the price of productkey 1.
The formula is structured like this
=NameOfTheTable[NameOfTheColumnToReturnTheValueOf]{PositionReturnedByListPositionOf}
But we why not change it into a function in PowerQuery so we use the function on all rows in a table or on any table.
The function can be created like this
The code
(lookupValue as any, lookupTable as table, lookupColumnName as text, returnColumnValue as text) => let // lookupTable= Products, // lookupColumnName = "ProductKey", // returnColumnValue = "Price", // lookupValue = 1, colLookup = Table.Column(lookupTable, lookupColumnName), colToReturn = Table.Column(lookupTable, returnColumnValue), lookup = List.PositionOf(colLookup, lookupValue, 0), Result = if lookup >=0 then colToReturn{lookup} else "Not found" in Result
The function takes 4 arguments –
lookupValue – The value to find – can be any type
lookupTable – The Table/Query to lookup in
lookupColumnName – The name of the column to lookup the value in
returnColumnValue – The name of the column from the table to return
The colLookup is a variable that uses the function Table.Column to return a list of values in the lookup column.
The colToReturn is a variable that uses the function Table.Column to return a list of values from the values you want to return column.
The lookup variable uses the List.PositionOf to find the position/index of the search value in the lookup column.
Result will use an if statement to test whether a position is found and if so returns the value at the position in the colToReturn list – other wise returns the text “Not Found”.
After this we can use the function in other tables to lookup the for instance the Product price like this – by added a invoke Custom Function Column
OBS – I haven’t tried this on a large table so be aware of any performance issues.
Hope you find this useful – and happy Querying
Here is a link to an example file – Link
Pingback: Replicating VLOOKUP with M – Curated SQL
Superb! I’m wanting to identify “sequences” in a table where a sequence is a run of records with the same value in a specific field, for example if the following were the list values in Field A {0,4,8,2,2,2,6,4,7,7,7,3,2,2,2,2,4,5} then I want to find the three sequences: 2,2,2 and 7,7,7 and 2,2,2,2. The difficulty I have is that independent sequences may have the same value (the 2s in the example). Using your function and an iterative “look back” I can now do my identification and assign each sequence the index value of the record at the start of the sequence. Thanks!
Hi Steve Glad you found it usefull /Erik
Big thanks for very detailed explanation, especially for pbix file.
I have applied this fx onto data base with 158k rows, which is coming initially from xls file of 25mb.
However, refresh of data is lagged afterwards, it says that updating data from xls file of 600 mb and keep counting up, instead of previous 25mb…
I fairly don’t understand logic of having fx function in query and increasing data within xls file, so will have to find another solution..
But otherwise it is really helpful feature.
Thanks
Hi Paul.
Glad you found it usefull – and I am not surprised that your dataset size would cause update performance issues – so thank you for sharing your case
BR
Erik
What do I do if I need it to return values that requires it consider 2 different lookup Columns? Example Lookup Column 1 would be if the years match and then lookup column 2 would be if the store matches then it should return a specific value.
Hi Michael, Can you construct an actual test case and I will be happy to solve it ? /Erik
I think I’m going to use this to store a list of OData URLs in an Excel table and just lookup the URL based on a “source reference” instead of copying and pasting every single URL in my queries.
I considered your approach and decided to do something else, which I can share.
Merge, then Expand. I used the Table.SelectColumns function to grab only the lookup column and return column(s) from a table with many columns. I thought this might avoid slowness. I’m finding a match of ID in the table called LookupTable, and returning the value ReturnValue from that record.
#”Merged Queries” = Table.NestedJoin(#”Sorted Rows”, {“ID”}, Table.SelectColumns(LookupTable,{“ID”,”ReturnValue”}), {“ID”}, “NewColumnName”, JoinKind.LeftOuter),
#”Expanded NewColumnName” = Table.ExpandTableColumn(#”Merged Queries”, “NewColumnName”, {“ReturnValue”}, {“ReturnValue”})
Nice 👍
Thanks for sharing that.
Is there any way to use this function to search the values on the same table?
For an example, I need to take the value of a colum 24 rows before the current row and put on a new column, but this way the function is done I’m not allowed to search on the same table I’m including the new column.
Could you provide an example dataset – and I will give it a shot
This is a sample (sorry, don’t know if there’s a better way to share it here):
Index Unity Value
1 Price 10
1 Un 1
1 Kg 2
2 Price 5
2 Un 2
2 Kg 1
3 Price 10
3 Un 3
3 Kg 6
4 Price 8
4 Un 1
4 Kg 1
5 Price 10
5 Un 1
5 Kg 1
And the result I need:
Index Price Un Kg
1 10 1 2
2 5 2 1
3 10 3 6
4 8 1 1
5 10 1 1
Thanks in advance for your help.
Hi again – you can do this by using the Table.Pivot function –
= Table.Pivot(x, List.Distinct(x[Unit]), “Unit”, “Value” )
where x is the table
/Erik
Or use the Pivot Column button in the Transform table to set it up via the interface
Hi Erik,
Very well explained, I’m new to this and I could understand exactly what was happening.
You are the only person that talks about these, I have a question though, I hope you can help me with this.
I tried your function (last bit at the end where you include it inside another table), which was very helpful by the way, but this function will only find match it if is exactly the same as the other table.
I was wondering if you knew a way to search inside the text, if found, search inside the other table and return the column, if that makes sense.
So using your example above:
If found 12 in a cell, instead of saying ” not found”, return “100 75”.
I found a partial solution to this but, it will only return the same word if found in a list (not case sensitive), I’m not sure if it will help but it might help if someone like me is trying to find a solution to this problem:
List.Accumulate
(
List,
“”,
(state, current) =>
if Text.Contains([Details], current, Comparer.OrdinalIgnoreCase)
then state & ” ” & current
else state
)
Thank you 🙂
Hi Pierre – thank you for your feedback –
When you refer to “12” to get “100 75” – – I guess you refer to the prices for productkey 1 and 2 in my example ?
You will have to have the product keys separated by a ; or # to be able to find and return the prices – if the product key is 11 it will be impossible to split correctly.
If that is possible I am sure I can create a working method – let me know if you want an example on that
Hi Erik,
Thanks for coming back to me so quickly.
You are right, it would be impossible if it was numbers, I just realised that.
I was just using your example above.
In my case it’s words, so for example, I have a table with 2 columns, one column with keywords(ingredients) such as:
Apple, carrot, watermelon, beef …
And another column next to it, called Category such as:
Fruit, Vegetable, Meat …
What I would like to do is to search for these keywords on each row of the column and if found return the category, so for example:
Cell contains: “Apples Beef”
The next column which has the formula would return ” Fruit Meat”
This would ignore any ending such as the “s” at the end and would return multiple values in one cell.
The formula above only helps me find the words inside each cell, but I would like to go an extra step and combine your function to return the other column just like VLookup.
The problem is that I’m new to Power Query and I’m working on this project to learn more about Power Query in the process.
I hope this makes sense 🙂
Also sorry for double posting for some reason I couldn’t see my first comment so I thought it didn’t go through.
Hi Erik Svensen,
Would it be possible to combine this solution and a formula that will search from a list of words inside every cell?
An example using your data above would something like this:
A cell contains “245” and the column would return “75 80 400”
I found a solution to search for the string inside the cell but I don’t know how to combine it with this solution.
Could you help me, please?
Hi – Please check my comments/question from your previous comment 🙂
Nice job … thanks!
Hi Erik,
I have been scouring the internet, whilst not knowing what I am looking for exactly and I think this post is as close to what I’m looking for as I am going to find. In my case, I am looking to use this feature but with the data meeting two lookup conditions (someone earlier in the chat had this same query).
In my case, I have a list of items (derogations) that have a document reference and a received date:
derog 1 – docref1 – received date
derog 2 – docref1 – received date
derog 3 – docref2 – received date
…
I also have another query that contains the document reference, the revision number and the published date:
docref1 – rev0 – published date
docref1 – rev1 – published date
docref1 – rev2 – published date
docref2 – rev0 – puclished date
…
I would like to create a calculated column in my first table with the revision number, based on the docref and the recevied date:
derog 1 – docref1 – received date – rev0
derog 2 – docref1 – recevied date – rev2
derog 3 – docref2 – recevied date – rev0
…
Is this possible and what is the best way to define my lookup table? i.e. having one published date or having a from/to range? If needed, I can provide a sample dataset.
Thank you very much in advance,
Scott
Hi Scott, please provide a dataset and your expected outcome and I will have a look at it – you can reach me at es @ catmansolution.com
Thank you Erik, I have just sent my example dataset and required outcome.
Hello Erik,
Could you, please, advise if it is possible to return value upon multiple different lookup columns?
Picture this,
Lookup table has columns:
ReturnedValue – Level1 – Level2 – Level3
value1-L1.1-null-null
value2-L1.1-L2.1-null
value3-L1.1-L2.2-null
value4-L1.1-L2.1-L3.1
value5-L1.1-L2.1-L3.2
Fact table has columns:
Level1 – Level2 – Level3 – Other columns
L1.1-null-null-…
L1.1-L2.1-null-…
L1.1-L2.2-null-…
L1.1-L2.1-L3.1-…
L1.1-L2.1-L3.2-…
I need to define single corresponding ReturnedValue for each row of the Fact table.
Expected outcome for the Fact table:
ReturnedValue – Level1 – Level2 – Level3 – Other columns
value1-L1.1-null-null-…
value2-L1.1-L2.1-null-…
value3-L1.1-L2.2-null-…
value4-L1.1-L2.1-L3.1-…
value5-L1.1-L2.1-L3.2-…
Logic: lookup by level1. If multiple values found (count of ReturnedValue >1), then lookup by level1 and level2. If still multiple values found (count of ReturnedValue >1), then lookup by level1 and level2 and level3. (I actually might have more levels, this is just for the illustration).
Thank you very much in advance!
Hi Stew,
Wouldn’t it be easier to create a column combining the columns to a key column and create a relationship between the two tables on that key ?
BR
Erik
Erik,
Thank you for your feedback!
The problem is that I have a very large amount of rows that will grow over time and those level lookup columns are text columns with sometimes many symbols (1-5 words). So I’m afraid for the performance in this case and thought it would be better to do this in Power Query. What would be the best approach?
Thank you.
Hi Stew – the number of rows does not have to be a problem but that depends on the source and if it is text/csv files it is a problem but if it is SQL server or another source that supports query folding then you can push the hard work to the source instead of power query – so as always it depends 🙂
The source is Excel files stored in SharePoint
The source is lots of Excel files stored in SharePoint
Hi Erik,
I think this post helps me but I need to step this function for a parameter value that will be used in sql statement. Could you help me?
Thank you so much!
Hi – you should consider importing the table/sql data and use relations between tables instead – otherwise feel free to post an example dataset and I will take a look at it
Great, thank you! Tried shift but not ctrl. 🙂
This has saved my day, great article!!
Glad to hear 🙂
Erik, Would it be possible to edit your original function query to act in the same capacity of vlookup when you drop the true or false does? Basically grabs the closest value when using numbers.
Hi Mike – should be possible – Would require the table to be sorted and then perhaps do a loop – will see if it can be done
I have a sample of the data set I’m using as a table in excel and how it functions. How can i get it to you?
es @ catmansolution.com
Hi Erik,
i’m so glad to find your article. It works, but i change my plans and then I got stuck.
In my Query I would like to find a value in the same table.
I would like to see the result of the previous month in the same line of the actual month. For this, I create a column key which is (Process Number + Actual Month (Key1)) and another one which is (Process Number + Previous Month (Key2)). So, based on Key2 I’m able to see the result of the previous month.
Can you help me with this?
Hi – could you send some demo data and the result you want ?
Where can I send you the file?
es @ catmansolution com