{"id":672,"date":"2025-05-17T06:56:31","date_gmt":"2025-05-17T06:56:31","guid":{"rendered":"https:\/\/datadandies.nl\/?p=672"},"modified":"2025-05-30T08:37:46","modified_gmt":"2025-05-30T08:37:46","slug":"672","status":"publish","type":"post","link":"https:\/\/datadandies.nl\/index.php\/2025\/05\/17\/672\/","title":{"rendered":"Multi column or multi condition JOIN using Power Query M"},"content":{"rendered":"\n<p>Ever wondered how to do a Multi-Column-JOIN in Power Query M?<\/p>\n\n\n\n<p>It is so simple to join TABLE_A to TABLE_B in SQL using multiple conditions on multiple columns:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-bottom-disabled cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.3rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * 1.3rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e\"><span style=\"background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e\">SQL<\/span><\/span><span role=\"button\" tabindex=\"0\" data-code=\"SELECT \n*\nFROM TABLE_A A\nJOIN TABLE_B B \n  ON A.ID = B.ID\n  AND A.DATE BETWEEN B.STARTDATE AND B.ENDDATE\" style=\"color:#D4D4D4;display:none\" aria-label=\"Kopieer\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">SELECT<\/span><span style=\"color: #D4D4D4\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">*<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">FROM<\/span><span style=\"color: #D4D4D4\"> TABLE_A A<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">JOIN<\/span><span style=\"color: #D4D4D4\"> TABLE_B B <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">ON<\/span><span style=\"color: #D4D4D4\"> A.ID = B.ID<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">AND<\/span><span style=\"color: #D4D4D4\"> A.DATE <\/span><span style=\"color: #569CD6\">BETWEEN<\/span><span style=\"color: #D4D4D4\"> B.STARTDATE <\/span><span style=\"color: #569CD6\">AND<\/span><span style=\"color: #D4D4D4\"> B.ENDDATE<\/span><\/span><\/code><\/pre><span style=\"display:flex;align-items:flex-end;padding:10px;width:100%;justify-content:flex-end;background-color:#1E1E1E;color:#c7c7c7;font-size:12px;line-height:1;position:relative\">SQL<\/span><\/div>\n\n\n\n<p>But how do we replicate this in Power Query M?<\/p>\n\n\n\n<p>Turns out we can add a column using the Power Query M function Table.SelectRows. Take a look at the image below.<\/p>\n\n\n\n<p>One downside to this approach is that the performance is terrible for large datasets. This is likely due to the fact that as far as I understand, a nested loop is used: each row of TABLE_A is checked against each row of TABLE_B.<\/p>\n\n\n\n<p>In SQL, JOINs like these perform much better for several reasons: indexing, stats, more efficient query plans like hash JOINs, etc. One thing worth exploring in order to improve performance of this method in Power Query M might be to first JOIN TABLE_A to TABLE_B using the ID column, and then apply the second date-based condition. I haven\u2019t explored this option yet, but if you\u2019re limited to Power Query M and need to make a multi column JOIN happen, that is something I would try.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro padding-bottom-disabled cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:1.3rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * 1.3rem);line-height:1.5rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e\"><span style=\"background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e\">Power Query<\/span><\/span><span role=\"button\" tabindex=\"0\" data-code=\"let\n  Source = ...\n\n  etc.\n\n  \/\/ Start logic multi condition JOIN\n  #&quot;AddColumnMultiConditionJoin&quot; = Table.AddColumn(\n    \/\/ Giving the fact table the &quot;alias&quot;: &quot;c&quot; (which is technically not an alias, but a lambda function parameter representing rows of the fact table. It functions as a loop where each row from the fact table &quot;p&quot; is checked against each row from the dimension table &quot;c&quot;)\n    #&quot;TableFromPreviousStep&quot;, &quot;Custom&quot;, (c)=&gt;             \n      Table.SelectRows(\n        \/\/ Giving the dimension table containing an ID-column and a start- and enddate column an &quot;alias&quot;: &quot;p&quot;\n        #&quot;DimensionTableWithIdColumnAndStartdateAndEnddate&quot;, (p)=&gt; \n            \/\/ Multi condition JOIN using...\n            c[ID_COLUMN] = p[ID_COLUMN]                     \/\/ ... ID_COLUMN and...\n            and c[DATE] &gt;= p[STARTDATE]                     \/\/ ... DATE must be larger than STARTDATE and... \n            and c[DATE] &lt;= p[ENDDATE]                       \/\/ ... DATE must be smaller than ENDDATE\n            )\n          )\nin\n  #&quot;AddColumnMultiConditionJoin&quot;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Kopieer\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">let<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  Source = ...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  etc.<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #6A9955\">\/\/ Start logic multi condition JOIN<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  #&quot;AddColumnMultiConditionJoin&quot; = Table.AddColumn(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Giving the fact table the &quot;alias&quot;: &quot;c&quot; (which is technically not an alias, but a lambda function parameter representing rows of the fact table. It functions as a loop where each row from the fact table &quot;p&quot; is checked against each row from the dimension table &quot;c&quot;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    #&quot;TableFromPreviousStep&quot;, <\/span><span style=\"color: #CE9178\">&quot;Custom&quot;<\/span><span style=\"color: #D4D4D4\">, (c)=&gt;             <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      Table.SelectRows(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\">\/\/ Giving the dimension table containing an ID-column and a start- and enddate column an &quot;alias&quot;: &quot;p&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        #&quot;DimensionTableWithIdColumnAndStartdateAndEnddate&quot;, (p)=&gt; <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Multi condition JOIN using...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            c[ID_COLUMN] = p[ID_COLUMN]                     <\/span><span style=\"color: #6A9955\">\/\/ ... ID_COLUMN and...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            and c[DATE] &gt;= p[STARTDATE]                     <\/span><span style=\"color: #6A9955\">\/\/ ... DATE must be larger than STARTDATE and... <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            and c[DATE] &lt;= p[ENDDATE]                       <\/span><span style=\"color: #6A9955\">\/\/ ... DATE must be smaller than ENDDATE<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">          )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  #&quot;AddColumnMultiConditionJoin&quot;<\/span><\/span><\/code><\/pre><span style=\"display:flex;align-items:flex-end;padding:10px;width:100%;justify-content:flex-end;background-color:#1E1E1E;color:#c7c7c7;font-size:12px;line-height:1;position:relative\">Power Query<\/span><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Ever wondered how to do a Multi-Column-JOIN in Power Query M? It is so simple to join TABLE_A to TABLE_B in SQL using multiple conditions on multiple columns: But how do we replicate this in Power Query M? Turns out we can add a column using the Power Query M function Table.SelectRows. Take a look&hellip;<\/p>\n<p class=\"more-link\"><a href=\"https:\/\/datadandies.nl\/index.php\/2025\/05\/17\/672\/\" class=\"themebutton\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[3,11,4],"class_list":["post-672","post","type-post","status-publish","format-standard","hentry","category-blog","tag-powerbi","tag-powerquery","tag-sql"],"_links":{"self":[{"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/posts\/672","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/comments?post=672"}],"version-history":[{"count":3,"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/posts\/672\/revisions"}],"predecessor-version":[{"id":676,"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/posts\/672\/revisions\/676"}],"wp:attachment":[{"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/media?parent=672"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/categories?post=672"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/datadandies.nl\/index.php\/wp-json\/wp\/v2\/tags?post=672"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}