<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-13611701</id><updated>2009-12-09T03:02:13.930+01:00</updated><title type='text'>Excel</title><subtitle type='html'>A blog about Excel</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.leaton.net/Excel/atom.xml'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-13611701.post-3953525732909162750</id><published>2009-12-09T02:56:00.002+01:00</published><updated>2009-12-09T03:02:07.199+01:00</updated><title type='text'>Calculating National Insurance</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://excel.leaton.net/uploaded_images/NationalInsurance-743755.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 252px; height: 101px;" src="http://excel.leaton.net/uploaded_images/NationalInsurance-743754.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Create the cells above and create names for each of the values from the names in the left column.&lt;br /&gt;&lt;br /&gt;Two functions are available, one for employee national insurance, one for employer.&lt;br /&gt;&lt;br /&gt;The calls are&lt;br /&gt;&lt;br /&gt;=NationalInsurance(50000.0,Lower_Earnings_Threshold,Upper_Earnings_Threshold,Class_1,Class_1___4)&lt;br /&gt;&lt;br /&gt;=EmployerNationalInsurance(50000.0,Lower_Earnings_Threshold,Class_1___Secondary)&lt;br /&gt;&lt;br /&gt;The code for these functions is this&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Function NationalInsurance( _&lt;br /&gt;   income As Double, _&lt;br /&gt;   lowerearnings As Double, _&lt;br /&gt;   upperearnings As Double, _&lt;br /&gt;   classonerate As Double, _&lt;br /&gt;   secondaryrate As Double _&lt;br /&gt;   ) As Double&lt;br /&gt;   NationalInsurance = 0#&lt;br /&gt;   If income &lt;= lowerearnings Then        &lt;br /&gt;       Exit Function    &lt;br /&gt;   End If    &lt;br /&gt;   If income &lt;= upperearnings Then        &lt;br /&gt;       NationalInsurance = (income - lowerearnings) * classonerate    &lt;br /&gt;   Else        &lt;br /&gt;       NationalInsurance = (upperearnings - lowerearnings) * classonerate + (income - upperearnings) * secondaryrate    &lt;br /&gt;   End If     &lt;br /&gt;End Function &lt;br /&gt;&lt;br /&gt;Function EmployerNationalInsurance( _&lt;br /&gt;   income As Double, _&lt;br /&gt;   lowerearnings As Double, _&lt;br /&gt;   secondaryrate As Double _&lt;br /&gt;   ) As Double&lt;br /&gt;   EmployerNationalInsurance = 0#&lt;br /&gt;   If income &lt;= lowerearnings Then&lt;br /&gt;       Exit Function&lt;br /&gt;   End If&lt;br /&gt;   EmployerNationalInsurance = (income - lowerearnings) * secondaryrate&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-3953525732909162750?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/3953525732909162750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=3953525732909162750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/3953525732909162750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/3953525732909162750'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2009/12/calculating-national-insurance.html' title='Calculating National Insurance'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-6786649268009071414</id><published>2009-12-09T02:53:00.003+01:00</published><updated>2009-12-09T02:56:36.531+01:00</updated><title type='text'>Calculating UK Tax</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://excel.leaton.net/uploaded_images/TaxRates-731699.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 153px; height: 82px;" src="http://excel.leaton.net/uploaded_images/TaxRates-731697.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;With this as a table, the following function call can be made from Excel&lt;br /&gt;&lt;br /&gt;=IncomeTax(50000.0,TaxRates)&lt;br /&gt;&lt;br /&gt;To calculate the tax paid. TaxRates is the range above.&lt;br /&gt;&lt;br /&gt;The code for this is as follows.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Function IncomeTax(income As Double, rates As Range) As Double&lt;br /&gt;    Dim i As Integer&lt;br /&gt;    Dim tax As Double&lt;br /&gt;    tax = 0&lt;br /&gt;    For i = 1 To rates.Rows.Count - 1&lt;br /&gt;        tax = tax + Application.Min(income, rates.Cells(i, 1)) * rates.Cells(i, 2)&lt;br /&gt;        income = Application.Max(0, income - rates.Cells(i, 1))&lt;br /&gt;    Next i&lt;br /&gt;    IncomeTax = tax + income * rates.Cells(rates.Rows.Count, 2)&lt;br /&gt;End Function&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-6786649268009071414?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/6786649268009071414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=6786649268009071414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/6786649268009071414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/6786649268009071414'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2009/12/calculating-uk-tax.html' title='Calculating UK Tax'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-115554762028770948</id><published>2006-08-14T11:26:00.000+02:00</published><updated>2006-08-14T11:27:00.303+02:00</updated><title type='text'></title><content type='html'>We often are given a chunk of data in Excel that we need to explore. Of course, the first tool you should pull out of your toolbox in cases like this is the trusty PivotTable (it slices, it dices!). But at times we have to dig a little deeper into the toolbox and pull out the in-cell bar chart. Here’s what it looks like.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://juiceanalytics.com/weblog/?p=236"&gt;link&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-115554762028770948?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/115554762028770948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=115554762028770948' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/115554762028770948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/115554762028770948'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2006/08/we-often-are-given-chunk-of-data-in.html' title=''/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-114675812332755346</id><published>2006-05-04T17:52:00.000+02:00</published><updated>2006-05-04T17:55:23.373+02:00</updated><title type='text'>Creating Names</title><content type='html'>Here is a better way to create a named range.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ActiveWorkbook.Names.Add &lt;br /&gt;    Name:="Data", &lt;br /&gt;    RefersToR1C1:="=" &amp; &lt;br /&gt;    Worksheets("Data").Cells(1, 1).CurrentRegion.Address(True, True, xlR1C1, False)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The secret is in using the Address method to generate a name that can be used by&lt;br /&gt;the Add method on a names collection.&lt;br /&gt;&lt;br /&gt;Why didn't Microsoft allow Excel to do the following&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; Range.Name = "Fred"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;as an operation?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-114675812332755346?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/114675812332755346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=114675812332755346' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114675812332755346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114675812332755346'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2006/05/creating-names.html' title='Creating Names'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-114665001185877791</id><published>2006-05-03T11:53:00.000+02:00</published><updated>2006-05-03T11:57:54.750+02:00</updated><title type='text'>Amazon.co.uk: Spreadsheet Check and Control: 47 key practices to detect and prevent errors: Books</title><content type='html'>&lt;a href="http://www.amazon.co.uk/exec/obidos/ASIN/190540400X/"&gt;Amazon.co.uk: Spreadsheet Check and Control: 47 key practices to detect and prevent errors: Books&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Learn how to: increase efficiency by avoiding rework; discover powerful formula auditing techniques; foil attempts to conceal data and formulas from you; reduce worry about costly and embarrassing mistakes; create spreadsheets faster by avoiding wasted time from lack of specification; present results with more confidence knowing that you have checked for errors; benefits to your organisation; ensure data quality and accuracy; protect against formula and operational errors; be able to demonstrate management of material risks; increase controls over spreadsheet based financial reporting; and reduce compliance costs for businesses in regulated sectors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-114665001185877791?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/114665001185877791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=114665001185877791' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114665001185877791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114665001185877791'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2006/05/amazoncouk-spreadsheet-check-and.html' title='Amazon.co.uk: Spreadsheet Check and Control: 47 key practices to detect and prevent errors: Books'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-114664903001646001</id><published>2006-05-03T11:37:00.000+02:00</published><updated>2006-05-03T11:37:10.040+02:00</updated><title type='text'>Buggy spreadsheets: Russian roulette for the corporation | The Register</title><content type='html'>&lt;a href="http://www.regdeveloper.co.uk/2006/05/03/buggy_spreadsheet/"&gt;Buggy spreadsheets: Russian roulette for the corporation  The Register&lt;/a&gt;: &lt;em&gt;"How many scenarios can you imagine where a momentary loss of concentration could cost over $1bn? Perhaps a nuclear power station meltdown...or if a currency trader hit a few wrong keys? Well, another possibility is a simple spreadsheet error.&lt;br /&gt;In October 2003, soon after announcing third quarter earnings, Fannie Mae had to restate its unrealised gains, increasing them by $1.2bn. This highly unwelcome outcome was said to stem from 'honest mistakes made in a spreadsheet used in the implementation of a new accounting standard'.&lt;br /&gt;The really, really bad news is that millions of similar errors are almost certainly being made every year, many of them in business-critical financial spreadsheets. Although they are the quintessential end-user tool, spreadsheets of any complexity are just as hard to write and maintain as any other kind of software - if they are to yield consistently accurate results, anyway."&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;br /&gt;Interesting article with several references to other articles about errors in spreadsheets.&lt;br /&gt;&lt;em&gt;&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-114664903001646001?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/114664903001646001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=114664903001646001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114664903001646001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114664903001646001'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2006/05/buggy-spreadsheets-russian-roulette.html' title='Buggy spreadsheets: Russian roulette for the corporation | The Register'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-114011165242693641</id><published>2006-02-16T18:40:00.000+01:00</published><updated>2006-02-16T18:40:52.440+01:00</updated><title type='text'>Create Custom Menu Items in Excel VBA</title><content type='html'>&lt;a href="http://www.ozgrid.com/VBA/custom-menus.htm"&gt;Create Custom Menu Items in Excel VBA&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-114011165242693641?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/114011165242693641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=114011165242693641' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114011165242693641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/114011165242693641'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2006/02/create-custom-menu-items-in-excel-vba.html' title='Create Custom Menu Items in Excel VBA'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-113878981850329246</id><published>2006-02-01T11:29:00.000+01:00</published><updated>2006-02-01T11:30:18.516+01:00</updated><title type='text'>Returning an array of values</title><content type='html'>http://www.cpearson.com/excel/returnin.htm&lt;br /&gt;&lt;br /&gt;How to return an array of values in VBA using a range function.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-113878981850329246?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/113878981850329246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=113878981850329246' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/113878981850329246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/113878981850329246'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2006/02/returning-array-of-values.html' title='Returning an array of values'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112377270212646593</id><published>2005-08-11T17:04:00.000+02:00</published><updated>2005-08-11T17:05:02.126+02:00</updated><title type='text'>Rule 20: User Name</title><content type='html'>&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  ' Declare for call to mpr.dll.&lt;br /&gt;   Declare Function WNetGetUser Lib "mpr.dll" _&lt;br /&gt;      Alias "WNetGetUserA" (ByVal lpName As String, _&lt;br /&gt;      ByVal lpUserName As String, lpnLength As Long) As Long&lt;br /&gt;&lt;br /&gt;   Const NoError = 0       'The Function call was successful&lt;br /&gt;&lt;br /&gt;   Sub GetUserName()&lt;br /&gt;&lt;br /&gt;      ' Buffer size for the return string.&lt;br /&gt;      Const lpnLength As Integer = 255&lt;br /&gt;&lt;br /&gt;      ' Get return buffer space.&lt;br /&gt;      Dim status As Integer&lt;br /&gt;&lt;br /&gt;      ' For getting user information.&lt;br /&gt;      Dim lpName, lpUserName As String&lt;br /&gt;&lt;br /&gt;      ' Assign the buffer size constant to lpUserName.&lt;br /&gt;      lpUserName = Space$(lpnLength + 1)&lt;br /&gt;&lt;br /&gt;      ' Get the log-on name of the person using product.&lt;br /&gt;      status = WNetGetUser(lpName, lpUserName, lpnLength)&lt;br /&gt;&lt;br /&gt;      ' See whether error occurred.&lt;br /&gt;      If status = NoError Then&lt;br /&gt;         ' This line removes the null character. Strings in C are null-&lt;br /&gt;         ' terminated. Strings in Visual Basic are not null-terminated.&lt;br /&gt;         ' The null character must be removed from the C strings to be used&lt;br /&gt;         ' cleanly in Visual Basic.&lt;br /&gt;         lpUserName = Left$(lpUserName, InStr(lpUserName, Chr(0)) - 1)&lt;br /&gt;      Else&lt;br /&gt;&lt;br /&gt;         ' An error occurred.&lt;br /&gt;         MsgBox "Unable to get the name."&lt;br /&gt;         End&lt;br /&gt;      End If&lt;br /&gt;&lt;br /&gt;      ' Display the name of the person logged on to the machine.&lt;br /&gt;      MsgBox "The person logged on this machine is: " &amp; lpUserName&lt;br /&gt;&lt;br /&gt;   End Sub&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112377270212646593?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112377270212646593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112377270212646593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112377270212646593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112377270212646593'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/08/rule-20-user-name.html' title='Rule 20: User Name'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112377263889500080</id><published>2005-08-11T17:03:00.000+02:00</published><updated>2005-08-11T17:03:58.906+02:00</updated><title type='text'>Rule 19: Machine Name</title><content type='html'>&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Private Declare Function GetComputerName Lib "kernel32" _&lt;br /&gt;    Alias "GetComputerNameA" _&lt;br /&gt;    (ByVal lpBuffer As String, nSize As Long) As Long&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Function ReturnComputerName() As String&lt;br /&gt;Dim rString As String * 255, sLen As Long, tString As String&lt;br /&gt;    tString = ""&lt;br /&gt;    On Error Resume Next&lt;br /&gt;    sLen = GetComputerName(rString, 255)&lt;br /&gt;    sLen = InStr(1, rString, Chr(0))&lt;br /&gt;    If sLen &gt; 0 Then&lt;br /&gt;        tString = Left(rString, sLen - 1)&lt;br /&gt;    Else&lt;br /&gt;        tString = rString&lt;br /&gt;    End If&lt;br /&gt;    On Error GoTo 0&lt;br /&gt;    ReturnComputerName = UCase(Trim(tString))&lt;br /&gt;End Function&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112377263889500080?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112377263889500080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112377263889500080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112377263889500080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112377263889500080'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/08/rule-19-machine-name.html' title='Rule 19: Machine Name'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112375745964424782</id><published>2005-08-11T12:46:00.000+02:00</published><updated>2005-08-11T12:50:59.646+02:00</updated><title type='text'>Rule 18: Using DB Code</title><content type='html'>Here is an example of using the DB Code&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;' Load Duration sheet&lt;br /&gt;Sub Load_Duration()&lt;br /&gt;    Dim sqlQry As String&lt;br /&gt;    Dim ds As String&lt;br /&gt;    Dim dbConn As ADODB.Connection&lt;br /&gt;    &lt;br /&gt;    ds = Format(Worksheets("Main").Range("Risk_Date"), "YYYYMMDD")&lt;br /&gt;    sqlQry = "select isin, duration, date from durations where date = '" &amp; ds &amp; "'"&lt;br /&gt;    WSDuration.Range("Duration").ClearContents&lt;br /&gt;    &lt;br /&gt;    Set dbConn = Db.OpenConnection_ODBC(GetDBParams("FASER", "_SERVER"), _&lt;br /&gt;                                        GetDBParams("FASER", "_DB"), _&lt;br /&gt;                                        GetDBParams("FASER", "_USER"), _&lt;br /&gt;                                        GetDBParams("FASER", "_PASSWORD"))&lt;br /&gt;    Call SQLToRangeName(dbConn, sqlQry, WSDuration, "Duration", True)&lt;br /&gt;    &lt;br /&gt;    If WSDuration.Range("Duration").Rows.count &lt; 2 Then &lt;br /&gt;        AddLogItem ("Load_Duration : Warning - no data retrieved for Duration")&lt;br /&gt;    End If&lt;br /&gt;End Sub&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pretty easy. The parameters are straight forward extracts from a sheet or a parameter file.&lt;br /&gt;&lt;br /&gt;Setting up the sql query is easy.&lt;br /&gt;&lt;br /&gt;Results go to one sheet.&lt;br /&gt;&lt;br /&gt;To further use the results, vlookups are the easy way. That means the first column should be the key for the table. The vlookup is then&lt;br /&gt;&lt;br /&gt;=vlookup (key, Duration, 2, FALSE)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112375745964424782?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112375745964424782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112375745964424782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112375745964424782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112375745964424782'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/08/rule-18-using-db-code.html' title='Rule 18: Using DB Code'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112375707947827591</id><published>2005-08-11T12:42:00.000+02:00</published><updated>2006-05-03T14:26:37.523+02:00</updated><title type='text'>Rule 18: Centralise DB code</title><content type='html'>Here is some centralised DB access code&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Option Explicit&lt;br /&gt;&lt;br /&gt;Private Enum ConnectionType&lt;br /&gt;    MSAccess = 0&lt;br /&gt;    Sybase = 1&lt;br /&gt;End Enum&lt;br /&gt;&lt;br /&gt;Private liveConnections As Collection&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Private Sub AddLiveConnection &lt;br /&gt;    (&lt;br /&gt;    ByVal key As String, &lt;br /&gt;    ByRef theConnection As adodb.connection&lt;br /&gt;    )&lt;br /&gt;    Call CheckLiveConnections&lt;br /&gt;    If Trim(key) &lt;&gt; "" _&lt;br /&gt;            And Not (theConnection Is Nothing) _&lt;br /&gt;            And LiveConnectionExists(key) = False _&lt;br /&gt;            And theConnection.State = adodb.adStateOpen _&lt;br /&gt;            Then&lt;br /&gt;        liveConnections.Add theConnection, key&lt;br /&gt;    End If&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Private Function GetLiveConnection(ByVal key As String) As adodb.connection&lt;br /&gt;    CheckLiveConnections&lt;br /&gt;    If CollectionItemExists(liveConnections, key) Then&lt;br /&gt;        Set GetLiveConnection = liveConnections(key)&lt;br /&gt;    Else&lt;br /&gt;        Set GetLiveConnection = Nothing&lt;br /&gt;    End If&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Private Function LiveConnectionExists(ByVal key As String) As Boolean&lt;br /&gt;    Dim db As adodb.connection&lt;br /&gt;    &lt;br /&gt;    Call CheckLiveConnections&lt;br /&gt;    If CollectionItemExists(liveConnections, key) Then&lt;br /&gt;        Set db = liveConnections(key)&lt;br /&gt;        If db.State = adStateOpen Then&lt;br /&gt;            LiveConnectionExists = True&lt;br /&gt;        Else&lt;br /&gt;            'The connection must have existed, but was not open, so delete it.&lt;br /&gt;            Set db = Nothing&lt;br /&gt;            liveConnections.Remove (key)&lt;br /&gt;        End If&lt;br /&gt;    End If&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Private Sub CheckLiveConnections()&lt;br /&gt;    'Need to check that the liveConnections array exists, as it may have died previously.&lt;br /&gt;    If liveConnections Is Nothing Then&lt;br /&gt;        Set liveConnections = New Collection&lt;br /&gt;    End If&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Private Function GetDBConnection&lt;br /&gt;    (&lt;br /&gt;    ByVal connType As ConnectionType, &lt;br /&gt;    ByVal info As String&lt;br /&gt;    ) As adodb.connection&lt;br /&gt;    Dim odbcStr As String&lt;br /&gt;    &lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    'Open a connection to the database&lt;br /&gt;    Set GetDBConnection = New adodb.connection&lt;br /&gt;    &lt;br /&gt;    Select Case connType&lt;br /&gt;        Case ConnectionType.MSAccess&lt;br /&gt;            'For access databases the info is the file path of the database&lt;br /&gt;            odbcStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=""" &amp; info &amp; """"&lt;br /&gt;        Case ConnectionType.Sybase&lt;br /&gt;            'For Sybase databases the info is the odbc string&lt;br /&gt;            odbcStr = info &amp; "Driver={SYBASE ASE ODBC Driver};"&lt;br /&gt;    End Select&lt;br /&gt;    &lt;br /&gt;    GetDBConnection.ConnectionString = odbcStr&lt;br /&gt;    GetDBConnection.Open&lt;br /&gt;    &lt;br /&gt;    Exit Function&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Function OpenConnection_Access(ByVal pathMDB As String) As adodb.connection&lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    Set OpenConnection_Access = GetDBConnection(MSAccess, pathMDB)&lt;br /&gt;    &lt;br /&gt;    Exit Function&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Function OpenConnection_ODBC&lt;br /&gt;    (&lt;br /&gt;    ByVal server As String, &lt;br /&gt;    ByVal db As String, &lt;br /&gt;    ByVal user As String, &lt;br /&gt;    ByVal password As String&lt;br /&gt;    ) As adodb.connection&lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    Dim odbcString As String&lt;br /&gt;    Dim key As String&lt;br /&gt;&lt;br /&gt;    'Build the key for the collection&lt;br /&gt;    key = server &amp; "_" &amp; db &amp; "_" &amp; user&lt;br /&gt;    &lt;br /&gt;    'Return the connection if it exists already&lt;br /&gt;    If LiveConnectionExists(key) Then&lt;br /&gt;        Set OpenConnection_ODBC = GetLiveConnection(key)&lt;br /&gt;    Else&lt;br /&gt;        odbcString = odbcString &amp; "Srvr=" &amp; server &amp; ";"&lt;br /&gt;        odbcString = odbcString &amp; "Database=" &amp; db &amp; ";"&lt;br /&gt;        odbcString = odbcString &amp; "Pwd=" &amp; password &amp; ";"&lt;br /&gt;        odbcString = odbcString &amp; "uid=" &amp; user &amp; ";"&lt;br /&gt;        Set OpenConnection_ODBC = GetDBConnection(Sybase, odbcString)&lt;br /&gt;        Call AddLiveConnection(key, OpenConnection_ODBC)&lt;br /&gt;    End If&lt;br /&gt;    &lt;br /&gt;    Exit Function&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Public Sub CloseDBConnection(ByRef dbConn As adodb.connection)&lt;br /&gt;&lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    'If there is a connection shut it down.&lt;br /&gt;    If Not (dbConn Is Nothing) Then&lt;br /&gt;        If dbConn.State = adodb.adStateOpen Then&lt;br /&gt;            dbConn.Close&lt;br /&gt;        End If&lt;br /&gt;        Set dbConn = Nothing&lt;br /&gt;    End If&lt;br /&gt;    &lt;br /&gt;    Exit Sub&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Private Function SQLRecordset&lt;br /&gt;    (&lt;br /&gt;    ByRef dbConn As adodb.connection, &lt;br /&gt;    ByVal sql As String&lt;br /&gt;    ) As adodb.Recordset&lt;br /&gt;&lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    Dim rs As adodb.Recordset&lt;br /&gt;    &lt;br /&gt;    If Not (dbConn Is Nothing) Then&lt;br /&gt;        'Open a recordset&lt;br /&gt;        Set rs = New adodb.Recordset&lt;br /&gt;        Call rs.Open(sql, dbConn, adOpenForwardOnly)&lt;br /&gt;        Set SQLRecordset = rs&lt;br /&gt;    Else&lt;br /&gt;        MsgBox "Cannot open recordset when there is no active database connection"&lt;br /&gt;    End If&lt;br /&gt;    &lt;br /&gt;    Exit Function&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Function SQLToArray&lt;br /&gt;    (&lt;br /&gt;    ByRef dbConn As adodb.connection, &lt;br /&gt;    ByVal sql As String&lt;br /&gt;    ) As Variant&lt;br /&gt;&lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    Dim rs As adodb.Recordset&lt;br /&gt;    &lt;br /&gt;    If Not (dbConn Is Nothing) Then&lt;br /&gt;        'Open a recordset&lt;br /&gt;        Set rs = New adodb.Recordset&lt;br /&gt;        Call rs.Open(sql, dbConn, adOpenDynamic)&lt;br /&gt;        SQLToArray = rs.GetRows()&lt;br /&gt;    Else&lt;br /&gt;        MsgBox "Cannot open recordset when there is no active database connection"&lt;br /&gt;    End If&lt;br /&gt;    &lt;br /&gt;    Exit Function&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Public Sub SQLToRangeName&lt;br /&gt;    (&lt;br /&gt;    ByRef dbConn As adodb.connection, &lt;br /&gt;    ByVal sql As String, &lt;br /&gt;    ByRef WSTarget As Worksheet, &lt;br /&gt;    ByVal rangeNameTarget As String, &lt;br /&gt;    ByVal headers As Boolean, &lt;br /&gt;    Optional ByVal cursorType As adodb.CursorTypeEnum = adodb.CursorTypeEnum.adOpenDynamic&lt;br /&gt;    )&lt;br /&gt;                                &lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    &lt;br /&gt;    Dim rs As adodb.Recordset&lt;br /&gt;    Dim rng As Range&lt;br /&gt;    Dim rowCount As Long&lt;br /&gt;    Dim fieldCount As Integer&lt;br /&gt;    &lt;br /&gt;    Set rng = WSTarget.Range(rangeNameTarget)&lt;br /&gt;    &lt;br /&gt;    If Not (dbConn Is Nothing) Then&lt;br /&gt;        'Open a recordset&lt;br /&gt;        Set rs = New adodb.Recordset&lt;br /&gt;        Call rs.Open(sql, dbConn, cursorType)&lt;br /&gt;        &lt;br /&gt;        'Copy the headers if required&lt;br /&gt;        If headers Then&lt;br /&gt;            For fieldCount = 0 To rs.Fields.Count - 1&lt;br /&gt;                rng.Cells(1, fieldCount + 1).Value = rs.Fields(fieldCount).Name&lt;br /&gt;            Next fieldCount&lt;br /&gt;        End If&lt;br /&gt;        &lt;br /&gt;        'Copy all the records&lt;br /&gt;        rowCount = rng.Cells(IIf(headers, 2, 1), 1).CopyFromRecordset(rs)&lt;br /&gt;        &lt;br /&gt;        'Check the sizes for the range&lt;br /&gt;        rowCount = rowCount + IIf(headers, 1, 0)&lt;br /&gt;        If rowCount = 0 Then rowCount = 1&lt;br /&gt;        If fieldCount = 0 Then fieldCount = 1&lt;br /&gt;        &lt;br /&gt;        'Resize the range&lt;br /&gt;        Dim TheSheet As String&lt;br /&gt;        Dim TopLeft As String&lt;br /&gt;        Dim BottomRight As String&lt;br /&gt;        Dim RefersToString As String&lt;br /&gt;            &lt;br /&gt;        TheSheet = rng.Worksheet.Name&lt;br /&gt;        TopLeft = rng.Cells(1, 1).address&lt;br /&gt;        BottomRight = rng.Cells(rowCount, fieldCount).address&lt;br /&gt;        RefersToString = "='" &amp; TheSheet &amp; "'!" &amp; TopLeft &amp; ":" &amp; BottomRight&lt;br /&gt;        Application.Names(rangeNameTarget).refersTo = RefersToString&lt;br /&gt;    Else&lt;br /&gt;        MsgBox "Cannot open recordset when there is no active database connection"&lt;br /&gt;    End If&lt;br /&gt;    &lt;br /&gt;    Exit Sub&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Public Function SQLExecute&lt;br /&gt;    (&lt;br /&gt;    ByRef dbConn As adodb.connection, &lt;br /&gt;    ByVal sql As String&lt;br /&gt;    ) As Long&lt;br /&gt;&lt;br /&gt;    On Error GoTo ErrorHandler&lt;br /&gt;    Dim recordsAffected As Long&lt;br /&gt;    &lt;br /&gt;    If Not (dbConn Is Nothing) Then&lt;br /&gt;        'Run the SQL&lt;br /&gt;        Call dbConn.Execute(sql, recordsAffected)&lt;br /&gt;    Else&lt;br /&gt;        MsgBox "Cannot open recordset when there is no active database connection"&lt;br /&gt;    End If&lt;br /&gt;    SQLExecute = recordsAffected&lt;br /&gt;    &lt;br /&gt;    Exit Function&lt;br /&gt;    &lt;br /&gt;ErrorHandler:&lt;br /&gt;    MsgBox Err.Description&lt;br /&gt;    &lt;br /&gt;End Function&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112375707947827591?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112375707947827591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112375707947827591' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112375707947827591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112375707947827591'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/08/rule-18-centralise-db-code.html' title='Rule 18: Centralise DB code'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112375673771797873</id><published>2005-08-11T12:33:00.000+02:00</published><updated>2005-08-11T12:38:57.726+02:00</updated><title type='text'>Rule 17: Logging</title><content type='html'>Two major problems&lt;br /&gt;&lt;br /&gt;1. Users are very bad at reporting errors.&lt;br /&gt;2. No one knows what systems attach to particular data sources.&lt;br /&gt;&lt;br /&gt;There is a solution that fixes both.&lt;br /&gt;&lt;br /&gt;When accessing data, you should go through a common code routine. This can then determine the following&lt;br /&gt;&lt;br /&gt;1. spreadsheet name&lt;br /&gt;2. database name&lt;br /&gt;3. database server&lt;br /&gt;4. database user&lt;br /&gt;5. local user&lt;br /&gt;6. local machine&lt;br /&gt;7. timestamp&lt;br /&gt;8. success or failure&lt;br /&gt;9. name of the query&lt;br /&gt;&lt;br /&gt;Now, this can all be logged to a very simple central database.&lt;br /&gt;&lt;br /&gt;Any failures can be reported on easily. A simple asp website is enough to report.&lt;br /&gt;&lt;br /&gt;Now if a database moves, you can tell which spreadsheets need changing. &lt;br /&gt;You know about any errors in extracting data&lt;br /&gt;You know who accesses what data.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112375673771797873?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112375673771797873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112375673771797873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112375673771797873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112375673771797873'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/08/rule-17-logging.html' title='Rule 17: Logging'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112256160563385199</id><published>2005-07-28T16:37:00.000+02:00</published><updated>2005-07-28T16:40:05.640+02:00</updated><title type='text'>Trick 3 - Variation on a theme</title><content type='html'>Reiner came up with a nice variation on Trick 2.&lt;br /&gt;&lt;br /&gt;We have a spreadsheet that is orthogonal. However, in the first column, in this case we have a trade id. &lt;br /&gt;&lt;br /&gt;The trick makes it neat to add a new trade. The event when something is entered in the sheet is there. When a new ISIN is added, the formulas from the row above are copied down automatically.&lt;br /&gt;&lt;br /&gt;The alternative is running lots of nasty macros.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112256160563385199?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112256160563385199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112256160563385199' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112256160563385199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112256160563385199'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/07/trick-3-variation-on-theme.html' title='Trick 3 - Variation on a theme'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112185290888127221</id><published>2005-07-20T11:39:00.000+02:00</published><updated>2005-07-20T12:04:41.100+02:00</updated><title type='text'>Trick 2 - Entering Numbers in Formulas</title><content type='html'>Here is a snippet from a sheet. X contains a number, and XX is X squared.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.leaton.net/Excel/uploaded_images/10-720098.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://www.leaton.net/Excel/uploaded_images/10-716755.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;i.e. The formula in cell X is "=X*X"&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.leaton.net/Excel/uploaded_images/sqrt-780327.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://www.leaton.net/Excel/uploaded_images/sqrt-777309.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now type 10 in cell XX overwriting the formula, and you get this.&lt;br /&gt;&lt;br /&gt;X now contains the square root of 10, and XX still contains the formula "=X*X"&lt;br /&gt;&lt;br /&gt;What's going on?&lt;br /&gt;&lt;br /&gt;Well, there is some code behind what is happening.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Sub Start()&lt;br /&gt;      Application.OnEntry = "Update"&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Sub Update()&lt;br /&gt;On Error GoTo errorhandler&lt;br /&gt;    With Application.Caller&lt;br /&gt;        If Application.Caller.Address = Range("XX").Address Then&lt;br /&gt;            Range("X") = Sqr(Application.Caller)&lt;br /&gt;            Range("XX").Formula = "=X*X"&lt;br /&gt;        End If&lt;br /&gt;    End With&lt;br /&gt;    Exit Sub&lt;br /&gt;errorhandler:&lt;br /&gt;    Exit Sub&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;First the start macro needs to be run. Typically this would sit in the autoexec macro.&lt;br /&gt;&lt;br /&gt;Then when something is entered on the sheet, the Update macro is called. This checks to see if you are overwritting the formula in XX. If it is, it calculates the square root, and repastes the formula back in cell XX.&lt;br /&gt;&lt;br /&gt;End result, code that works both ways.&lt;br /&gt;&lt;br /&gt;If there is a function such as eval in vba, the square root call could also be parameterised.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112185290888127221?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112185290888127221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112185290888127221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112185290888127221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112185290888127221'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/07/trick-2-entering-numbers-in-formulas.html' title='Trick 2 - Entering Numbers in Formulas'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112090259040532431</id><published>2005-07-09T11:49:00.000+02:00</published><updated>2005-07-09T11:49:50.406+02:00</updated><title type='text'>Download details: Excel 2003/2002 Add-in: MSN Money Stock Quotes</title><content type='html'>&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=485FCCD8-9305-4535-B939-3BF0A740A9B1&amp;amp;displaylang=EN"&gt;Download details: Excel 2003/2002 Add-in: MSN Money Stock Quotes&lt;/a&gt;: "This add-in for Excel 2003 and Excel 2002 allows you to get dynamic stock quotes from the MSN� Money� Web site. The tools and features found in Excel are particularly well suited to analyzing financial data such as stocks. This add-in allows you to easily gather and study the stocks of interest to you, refresh your quotes when you want, and readily change or modify the quotes gathered."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112090259040532431?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112090259040532431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112090259040532431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112090259040532431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112090259040532431'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/07/download-details-excel-20032002-add-in.html' title='Download details: Excel 2003/2002 Add-in: MSN Money Stock Quotes'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-112090208245797235</id><published>2005-07-09T11:41:00.000+02:00</published><updated>2005-07-09T11:41:22.470+02:00</updated><title type='text'>Office Tips and Hints Blog</title><content type='html'>&lt;a href="http://www.klippert.com/TCC/Blog/2005/06/excel-data-comparison-no-formulas-data.html"&gt;Office Tips and Hints Blog&lt;/a&gt;: "The Data Consolidation technique allows you to compare lists quickly and easily.&lt;br /&gt;&lt;br /&gt;With the Consolidation technique, you can identify the number of duplicate entries in two or more lists without using a formula.&lt;br /&gt;(not that it's easier, just that there are no formulas) "&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-112090208245797235?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/112090208245797235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=112090208245797235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112090208245797235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/112090208245797235'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/07/office-tips-and-hints-blog.html' title='Office Tips and Hints Blog'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111962567480003039</id><published>2005-06-24T16:56:00.000+02:00</published><updated>2005-06-27T11:50:37.076+02:00</updated><title type='text'>Rule 16: StatusBar</title><content type='html'>Use the Status bar to report information back to the user whilst code is being executed.&lt;br /&gt;&lt;br /&gt;For example, if several files or database queries are being run, then&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Application.StatusBar = "Loading file 1 ..."&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;will display a message on the status bar.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Application.StatusBar = False&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Will remove the value on the status bar.&lt;br /&gt;&lt;br /&gt;However, we are then back with the issue of nested calls.&lt;br /&gt;&lt;br /&gt;Its much better to create two utility functions, with the call, PushStatusMessage, and PopStatusMessage that creates a stack of status messages.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Private Const MaxStatusMessage As Integer = 100&lt;br /&gt;Dim StatusMessages(MaxStatusMessage) As String&lt;br /&gt;Dim StatusMessageCount As Integer&lt;br /&gt;&lt;br /&gt;Public Sub PushStatusMessage(message As String)&lt;br /&gt;    If StatusMessageCount = MaxStatusMessage Then&lt;br /&gt;        MsgBox "Status message stack is full"&lt;br /&gt;        Exit Sub&lt;br /&gt;    End If&lt;br /&gt;    StatusMessages(StatusMessageCount) = message&lt;br /&gt;    StatusMessageCount = StatusMessageCount + 1&lt;br /&gt;    Application.StatusBar = message&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Public Sub PopStatusMessage()&lt;br /&gt;    If StatusMessageCount = 0 Then&lt;br /&gt;        'MsgBox "Status message stack is empty"&lt;br /&gt;        Exit Sub&lt;br /&gt;    End If&lt;br /&gt;    StatusMessageCount = StatusMessageCount - 1&lt;br /&gt;    If StatusMessageCount = 0 Then&lt;br /&gt;        Application.StatusBar = False&lt;br /&gt;    Else&lt;br /&gt;        Application.StatusBar = StatusMessages(StatusMessageCount - 1)&lt;br /&gt;    End If&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Public Sub Test()&lt;br /&gt;    PushStatusMessage ("Test 1")&lt;br /&gt;    PushStatusMessage ("Test 2")&lt;br /&gt;    PopStatusMessage&lt;br /&gt;    PopStatusMessage&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111962567480003039?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111962567480003039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111962567480003039' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111962567480003039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111962567480003039'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-16-statusbar.html' title='Rule 16: StatusBar'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111962476717597474</id><published>2005-06-24T16:47:00.000+02:00</published><updated>2005-06-24T16:52:47.180+02:00</updated><title type='text'>Rule 15: Screen Updating</title><content type='html'>There is a flag Application.ScreenUpdating that can be set to True or False.&lt;br /&gt;&lt;br /&gt;Setting it to False whilst building up code makes the application run faster.&lt;br /&gt;&lt;br /&gt;However, in order to write code where you can nest calls means that each subroutine has to remember the state of the flag, and reset it when you exit the subroutine. If there is an early exit, or exception, the flag will not be restored. &lt;br /&gt;&lt;br /&gt;One possible solution is a utility subroutine that keeps a stack of the values. Its certainly easier than maintaining flags by hand.&lt;br /&gt;&lt;br /&gt;However, there is another approach. Just set the flag in the button code. That will always be at the top level so only one flag is needed. Just make sure its caught in the case of errors.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Private Sub CommandButton1_Click()&lt;br /&gt;    Dim su As Boolean&lt;br /&gt;    su = Application.ScreenUpdating&lt;br /&gt;    Application.ScreenUpdating = False&lt;br /&gt;On Error GoTo finish&lt;br /&gt;    ' Do some work here&lt;br /&gt;    Application.ScreenUpdating = su&lt;br /&gt;    Exit Sub&lt;br /&gt;finish:&lt;br /&gt;    Application.ScreenUpdating = su&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111962476717597474?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111962476717597474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111962476717597474' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111962476717597474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111962476717597474'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-15-screen-updating.html' title='Rule 15: Screen Updating'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111934448463257398</id><published>2005-06-21T10:59:00.000+02:00</published><updated>2005-06-21T11:50:04.660+02:00</updated><title type='text'>Trick 1: Reconciliation</title><content type='html'>Quite often there is a need to do quick reconcilliations between two different systems.&lt;br /&gt;&lt;br /&gt;Take a simple example. You are converting from system A to system B and need to make sure all the items are loaded into system B, and that a calculated value agrees.&lt;br /&gt;&lt;br /&gt;How does one do this in Excel?&lt;br /&gt;&lt;br /&gt;First we need to load the data into Excel. This can be done in various ways, but ADODB is probably the best.&lt;br /&gt;&lt;br /&gt;The data needs to be loaded in a certain form, and this diagram illustrates what is required.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.leaton.net/Excel/images/Reconciliation1.png" /&gt;&lt;br /&gt;&lt;br /&gt;The first column contains the name of the source system. The second column contains the key we need to use to match. The last column contains the calculated value. We load up all the rows from system A, then append the rows from system B.&lt;br /&gt;&lt;br /&gt;When we load the calculated value from the second system, we negate the number. More on this later.&lt;br /&gt;&lt;br /&gt;Now we can proceed to phase two. We select all the data, and then build a pivot table from the results. The source goes in the column headers. The key goes in the row, and the calculated value goes in the data area.&lt;br /&gt;&lt;br /&gt;The pivot table will now look like this.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.leaton.net/Excel/images/Reconciliation2.png" /&gt;&lt;br /&gt;&lt;br /&gt;So what do we have. Anything with a blank in the A or B column means a missing or extra item. When there are two items, but a non zero grand total for the row, this grand total shows the difference.&lt;br /&gt;&lt;br /&gt;1. There is a blank in the B column. That means an item in system A doesn't exist in system B&lt;br /&gt;&lt;br /&gt;2. We have an item in both, and a zero grand total. That means a perfect match.&lt;br /&gt;&lt;br /&gt;3. We have an item in both, but the values are different. 3 and 3.1 or a difference of 0.1&lt;br /&gt;&lt;br /&gt;4. A blank in column A means an item in system B exists, where as it doesn't exists in system A&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Its as quick as that.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.leaton.net/Excel/images/Reconciliation3.png" /&gt;&lt;br /&gt;&lt;br /&gt;This shows what happens if you put the key or source in the data area. Normally a key would be a string, so it won't sum the data, it counts it. Here we can quickly see anything with a 1 in the data illustrates a missing value. The grand totals of the columns show the number of items from each source.&lt;br /&gt;&lt;br /&gt;If you were doing this as part of a conversion, it pays to automate the process. For example, you could build some macros that download all the data, then build the pivot table.&lt;br /&gt;&lt;br /&gt;Once the pivot table is built, you can write a macro that hides the good data, just displaying the bad or vice versa.&lt;br /&gt;&lt;br /&gt;If you do this, another enhancement is to add on a name to sign off the differences. Then all you need to do as part of a big bang conversion is to run the reconciliation, filter the good items out. That then needs to be signed off by the business, and filed. &lt;br /&gt;&lt;br /&gt;This is probably the best Excel trick I have come across. Its not obvious at all that Excel can do things like this without doing a lot of work. &lt;br /&gt;&lt;br /&gt;Thanks Dom!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111934448463257398?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111934448463257398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111934448463257398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111934448463257398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111934448463257398'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/trick-1-reconciliation.html' title='Trick 1: Reconciliation'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111928471164229476</id><published>2005-06-20T18:14:00.000+02:00</published><updated>2005-06-20T18:25:11.646+02:00</updated><title type='text'>Rule 14: Give Modules meaningful names</title><content type='html'>Module1 is not a meaningful name. Point made.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111928471164229476?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111928471164229476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111928471164229476' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111928471164229476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111928471164229476'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-14-give-modules-meaningful-names.html' title='Rule 14: Give Modules meaningful names'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111928401269596846</id><published>2005-06-20T18:06:00.000+02:00</published><updated>2005-06-20T18:13:32.696+02:00</updated><title type='text'>Rule 13: VBA Formulas versus Worksheet formulas</title><content type='html'>Quite often there is a choice. Write a formula in the worksheet, or produce some VBA code. How does one make the decision?&lt;br /&gt;&lt;br /&gt;If there is conditional logic, then the first port of call is a VBA function. Its very difficult to read conditional logic in a worksheet formula, and they also tend to be quite long.&lt;br /&gt;&lt;br /&gt;If the partial results are meaningful, then put these on the spreadsheet and break the formulas down in their component parts.&lt;br /&gt;&lt;br /&gt;For example, if profit and loss is made up of different parts, cash, mark to market, transaction costs, fees etc, then a column for each of the parts makes sense. Then they can be totaled in the profit and loss column. If necessary, the other columns can be hidden. It makes debugging and analysis easier.&lt;br /&gt;&lt;br /&gt;Putting the formula into VBA also gives a name to what the formula intends to achieve. ie. =B2+C2+D2 doesn't convey much meaning. =Cash(A2) + MarkToMarket(A2) + TCosts(A2) + Fees(A2) makes a lot more sense, even if you have to dig around for the details.&lt;br /&gt;&lt;br /&gt;Putting the formulas into VBA also enables their definition to be in one place and one place only. ie. Code it once, not cut and paste the formula everywhere. The code can then be moved out to an XLA an centralised.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111928401269596846?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111928401269596846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111928401269596846' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111928401269596846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111928401269596846'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-13-vba-formulas-versus-worksheet.html' title='Rule 13: VBA Formulas versus Worksheet formulas'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111928354631301163</id><published>2005-06-20T18:01:00.000+02:00</published><updated>2005-06-20T18:05:46.316+02:00</updated><title type='text'>Rule 12: The macro recorder produces bad code</title><content type='html'>The macro recorder produces bad code. Cut and paste, select / selection has been covered. It does other things too that aren't particularly good.&lt;br /&gt;&lt;br /&gt;For example, it doesn't know about named ranges. As such it uses A1 style references all the time. &lt;br /&gt;&lt;br /&gt;These should be cleaned up.&lt;br /&gt;&lt;br /&gt;The code is very much a &lt;a href="http://en.wikipedia.org/wiki/Stream_of_consciousness"&gt;stream of conciousness&lt;/a&gt; type of approach to coding. Its much better to put some structure to the code. &lt;br /&gt;&lt;br /&gt;Break the macro down into subroutines. &lt;br /&gt;&lt;br /&gt;Rename the MacroN name of the recording to something that makes sense.&lt;br /&gt;&lt;br /&gt;Remove the select / selection  from the code&lt;br /&gt;&lt;br /&gt;Remove the copy / paste constructs.&lt;br /&gt;&lt;br /&gt;Think about any loops that make the code easier.&lt;br /&gt;&lt;br /&gt;What about variables? Should things be declared as variables?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111928354631301163?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111928354631301163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111928354631301163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111928354631301163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111928354631301163'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-12-macro-recorder-produces-bad.html' title='Rule 12: The macro recorder produces bad code'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111927813101726803</id><published>2005-06-20T16:29:00.000+02:00</published><updated>2005-06-20T16:36:20.346+02:00</updated><title type='text'>Rule 11: Hungarian Notation is bad</title><content type='html'>Its quite easy to show why Hungarian notation is bad, and its a point that is often missed in the religious wars on the subject.&lt;br /&gt;&lt;br /&gt;If you were designing a database or even an Excel spreadsheet, it would be an awful spreadsheet if the user had to enter the same number in lots of cells. &lt;br /&gt;&lt;br /&gt;The principle that should be followed is to have one cell storing the data and refer to that cell. ie. Store the data once.&lt;br /&gt;&lt;br /&gt;Hungarian notation goes against that priciple. Instead of storing the type of something in one place, its stores it everywhere it is used.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Dim icRow as Integer&lt;br /&gt;...&lt;br /&gt;icRow = icRow + 1&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here the type, an integer counter is stored and repeated everytime the variable is used instead of once, in the dim statement.&lt;br /&gt;&lt;br /&gt;If you want to change the type to a long, you have to change the dim, and everytime its used. If you code is used by others, its a real problem. Just your own code is bad enough.&lt;br /&gt;&lt;br /&gt;Instead just do this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Dim row as Integer 'index to the rows in the range&lt;br /&gt;...&lt;br /&gt;row = row + 1&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then you can change the type in once place and one place only. &lt;br /&gt;The intent comes from the comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111927813101726803?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111927813101726803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111927813101726803' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111927813101726803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111927813101726803'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-11-hungarian-notation-is-bad.html' title='Rule 11: Hungarian Notation is bad'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13611701.post-111927753784208473</id><published>2005-06-20T16:18:00.000+02:00</published><updated>2005-06-20T16:25:37.843+02:00</updated><title type='text'>Rule 10: Copy and Paste in VBA is evil</title><content type='html'>Just like select and selection, copy and paste in VBA codes is also evil. Its a side effect problem again and it can be avoided.&lt;br /&gt;&lt;br /&gt;Here is some typical generated code.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    Range("A13:B23").Select&lt;br /&gt;    Selection.Copy&lt;br /&gt;    Range("A26:B36").Select&lt;br /&gt;    ActiveSheet.Paste&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Taking out the select, we still have a problem.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    Range("A13:B23").Copy&lt;br /&gt;    Range("A26:B36").Paste&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It still has a side effect of putting some values in the clipboard.&lt;br /&gt;&lt;br /&gt;Here is some code that does the job without any side effects.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    Range("A26:B36").value = Range("A13:B23").value&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Shorter and side effect free.&lt;br /&gt;&lt;br /&gt;It also means the user isn't surprised if they run a macro and then try and paste what they thought was in the clipboard into a new range or cell.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13611701-111927753784208473?l=excel.leaton.net%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/111927753784208473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=13611701&amp;postID=111927753784208473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111927753784208473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13611701/posts/default/111927753784208473'/><link rel='alternate' type='text/html' href='http://excel.leaton.net/2005/06/rule-10-copy-and-paste-in-vba-is-evil.html' title='Rule 10: Copy and Paste in VBA is evil'/><author><name>Nick</name><uri>http://www.blogger.com/profile/06783119146180259097</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='11701999139707375230'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>