<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>VBA on Hat Full of Data</title><link>https://hatfullofdata.blog/categories/vba/</link><description>Recent content in VBA on Hat Full of Data</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><lastBuildDate>Sat, 08 Mar 2025 20:41:19 +0000</lastBuildDate><atom:link href="https://hatfullofdata.blog/categories/vba/index.xml" rel="self" type="application/rss+xml"/><item><title>VBA – Using Dictionaries to improve searching</title><link>https://hatfullofdata.blog/vba-using-dictionaries-to-improve-searching/</link><pubDate>Sat, 08 Mar 2025 20:41:16 +0000</pubDate><guid>https://hatfullofdata.blog/vba-using-dictionaries-to-improve-searching/</guid><description>&lt;p&gt;In VBA programming, dictionaries are invaluable tools that allow you to store key-value pairs efficiently. Checking a list of values to see if it contains a value is a regular requirement in many projects. The obvious solution in VBA is the values in an array and loop through till you find or don’t find the value. On a recent project, I was reminded that another solution is to use dictionaries, which have the exist method that quickly returns a true or false.&lt;/p&gt;
&lt;h2 id="vba-project-references"&gt;VBA Project References
&lt;/h2&gt;&lt;p&gt;Dictionaries are part of the Microsoft Scripting Runtime library which is not loaded by default. Within VBA in your Office app, in the Tools menu select References. From the list of available references tick Microsoft Scripting Runtime.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Adding Microsoft Scripting Runtime library so you can use dictionaries" class="gallery-image" data-flex-basis="293px" data-flex-grow="122" height="364" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/vba-using-dictionaries-to-improve-searching/image.png" width="445"&gt;&lt;/p&gt;
&lt;p&gt;Once the library is loaded you can now declare a variable as a dictionary.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Dim dictNames as Scripting.Dictionary
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="initialising-the-dictionary"&gt;Initialising the Dictionary
&lt;/h2&gt;&lt;p&gt;Dictionaries need initialising before you can use them. This can be done in the declaration of the variable or as a separate statement. I personally prefer the separate statement, means I get to chose when the variable is created.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39; === Part of the declaration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Dim dictNames As New Scripting.Dictionary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39; === Separate statement to initialise
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Dim dictNames As Scripting.Dictionary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Set dictNames = New Scripting.Dictionary
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="adding-items-to-dictionaries"&gt;Adding Items to Dictionaries
&lt;/h2&gt;&lt;p&gt;Dictionary entries have 2 parts, key and item. The key is used when checking to see if a dictionary entry exists and the item value is returned by using the key. So if all you are using the dictionary for is to have a searchable list the item value could be the same as the key or a constant.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39; === Add a dictionary entry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dictNames.Add Key:=&amp;#34;Adam&amp;#34;, Item:=&amp;#34;0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="checking-for-an-item-in-a-dictionary"&gt;Checking for an item in a dictionary
&lt;/h2&gt;&lt;p&gt;Once you have values in the dictionary you can check if a key value exists in the dictionary. The Exists method returns a Boolean based on if it can find the key value.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39; === Check for a key in the dictionary
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;If dictNames.Exists(Key:=&amp;#34;Adam&amp;#34;) Then
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MsgBox &amp;#34;Adam is in the list&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Else
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MsgBox &amp;#34;Adam is not in the list&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;End If
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="compare-a-dictionaries-to-an-arrays"&gt;Compare a dictionaries to an arrays
&lt;/h2&gt;&lt;p&gt;The data analyst in me wanted to check how each method compared. I expected the arrays method of looping through till you found or didn’t find would be slower. Both methods are fast so by doing 10,000 searches on a list 4,000 long with 25% of not found values the dictionary method won, but if the values were all found it was very close. Speed is not the only concern though when coding.&lt;/p&gt;
&lt;p&gt;The winner for me was the dictionary code was simpler, which reduces the technical debt of VBA code often written and maintained by business developers. The code below is to check if the value in strName is in an array or in a dictionary.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39; === Array Method
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;For i = LBound(arrNames) To UBound(arrNames)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; If arrNames(i) = strName Then
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; blnFound = True
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Exit For
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; End If
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Next i
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#39; === Dictionary Method
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;blnFound = dictNames.Exists(strName)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;VBA is not leaving soon, however much every IT department would like it to vanish. Just because most VBA programmers are not professional coders, it doesn’t mean VBA can’t be written well. Adding references to helpful libraries is good practice and will help in the long term. If there is concern for future coders understanding dictionaries add links in the comments of your code to the references below.&lt;/p&gt;
&lt;h2 id="references"&gt;References
&lt;/h2&gt;&lt;p&gt;Microsoft’s documentation is limited but can be found here &lt;a class="link" href="https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/dictionary-object" target="_blank" rel="noopener"
 &gt;https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/dictionary-object&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Paul Kelly has written a better blog with examples – &lt;a class="link" href="https://excelmacromastery.com/vba-dictionary/" target="_blank" rel="noopener"
 &gt;https://excelmacromastery.com/vba-dictionary/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="vba-posts"&gt;VBA Posts
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/" target="_blank" rel="noopener"
 &gt;VBA to Edit a Power Query Parameter Value&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query – VBA to Edit a Parameter Value</title><link>https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/</link><pubDate>Wed, 21 Apr 2021 17:04:16 +0000</pubDate><guid>https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/</guid><description>&lt;img src="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/cover.png" alt="Featured image of post Power Query – VBA to Edit a Parameter Value" /&gt;&lt;p&gt;This post is to document how to use Excel VBA to edit a parameter value without using the a cell reference in Power Query. My query was using Web.Contents which works with parameters in Excel Power Query1 but doesn’t like a function as part of the path.&lt;/p&gt;
&lt;p&gt;I started with Chris Webb’s great post on using an Excel named range and Web.Contents gave me problems. I would try Chris Webb’s method first which is found here &lt;a class="link" href="https://blog.crossjoin.co.uk/2014/07/22/working-with-excel-named-ranges-in-power-query/" target="_blank" rel="noopener"
 &gt;https://blog.crossjoin.co.uk/2014/07/22/working-with-excel-named-ranges-in-power-query/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So I want a button to take the value from a cell and update the value in a parameter. I searched the web and found one solution buried in a MrExcel forum so I’m documenting the solution here mostly so I can find it again later.&lt;/p&gt;
&lt;h3 id="vba-code-to-edit-a-parameter-value"&gt;VBA Code to Edit a Parameter Value
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Sub ChangeParameterValue(ParameterName As String, ParameterValue As String)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Dim qry As WorkbookQuery
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Dim formula As Variant
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;=== Get the query
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Set qry = ThisWorkbook.Queries(ParameterName)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;=== Split the formula into 3 parts and update the second one
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; formula = Split(qry.formula, Chr(34), 3)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; formula(1) = ParameterValue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;=== Update the parameter value
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; qry.formula = Join(formula, Chr(34))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;End Sub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="description"&gt;Description
&lt;/h3&gt;&lt;p&gt;The formula property of a query is really weird and hard to construct so the above function splits on Chr(34), which is a “. It then updates the middle value to the new value and then sticks the three values back together again.&lt;/p&gt;
&lt;p&gt;The original forum post I got the solution from can be found at &lt;a class="link" href="https://www.mrexcel.com/board/threads/vba-code-to-edit-power-query-data-source-settings.1146964/" target="_blank" rel="noopener"
 &gt;https://www.mrexcel.com/board/threads/vba-code-to-edit-power-query-data-source-settings.1146964/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;p&gt;1 – Web.Contents varies in different versions of Power Query so test carefully and do not assume you can copy and paste queries.&lt;/p&gt;
&lt;h2 id="more-power-query-posts"&gt;More Power Query Posts
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Custom Handwritten Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/" target="_blank" rel="noopener"
 &gt;Replace Values for Whole Table&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-ai-insights-error/" target="_blank" rel="noopener"
 &gt;AI Insights Error&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/" target="_blank" rel="noopener"
 &gt;VBA to Edit a Parameter Value&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/" target="_blank" rel="noopener"
 &gt;Dynamic Data Source and Web.Contents()&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-get-previous-row-data/" target="_blank" rel="noopener"
 &gt;Get Previous Row Data&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-creating-new-parameters/" target="_blank" rel="noopener"
 &gt;Creating New Parameters&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/" target="_blank" rel="noopener"
 &gt;Fixing Missing Columns Dynamically&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handling-null-values/" target="_blank" rel="noopener"
 &gt;Handling Null Values Properly&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>