What's the best/most efficient way to set Variables for Columns

Shloime

Board Regular
Joined
Oct 25, 2023
Messages
60
Office Version
  1. 365
  2. 2021
  3. 2019
  4. 2016
Platform
  1. Windows
I have Excel files with many macros that retrieve or write data across different sheets. I want a reliable way to set variables for specific columns so that:

  1. They automatically adjust if columns are added, removed, or rearranged.
  2. I can quickly update them if I change a column title (e.g., from "Names" to "First Name").
  3. The column variables are accessible across all modules/subs, so I don’t have to redefine them repeatedly.
or example, on "Sheet1" (with VBA code name S1), I have a constant header row (SHr) with column titles (which is not necessarily in row 1). I currently use this code to find the column for "First Name":
VBA Code:
S1colFN = Application.Match("First Name", S1.Rows(SHr), 0)

This approach works if "First Name" is moved to a different column. However, I would need to set these variables in each module or sub, so any change in column title (like "First Name" to "Names") means updating each instance manually.

To simplify this, I created a single module with constants for each header row and a function to retrieve the column numbers based on column names:

VBA Code:
Public Const NMHDr As Integer = 10

Function ColVar(CV As String) As Integer
    Dim cn As Integer
    Select Case CV
        Case "NMcolHO"
            cn = Application.Match("Holiday", NM.Rows(NMHDr), 0)
        Case "NMcolID"
            cn = Application.Match("ID", NM.Rows(NMHDr), 0)
        Case "NMcolSN"
            cn = Application.Match("Surname", NM.Rows(NMHDr), 0)
    End Select
    ColVar = cn
End Function
the in every Sub i declare the variables i need to use is that like:
VBA Code:
Dim NMcolID as integer
NMcolID=colvar("NMcolID")
Is there a more efficient way to manage the column references, making them easier to maintain and update across multiple modules?
 

Excel Facts

Links? Where??
If Excel says you have links but you can't find them, go to Formulas, Name Manager. Look for old links to dead workbooks & delete.
Ok that's an option. But I have work that I don't use tables
That's a shame - make life so much easier

If you just want to get the column number for any worksheet heading then try this update to your approach & see if will work for you

Place in STANDARD module
VBA Code:
Function GetColumn(ByVal HeaderName As String, Optional ByVal sh As Object, Optional ByVal HeaderRow As Long = 1) As Long
Dim HeaderArr As Variant, m As Variant
If sh Is Nothing Then Set sh = ActiveSheet
HeaderArr = sh.Rows(HeaderRow).Value2
m = Application.Match(HeaderName, HeaderArr, 0)
GetColumn = IIf(IsError(m), 1, CLng(m))
End Function

Function has three parameters

- HeaderName (string) = the name of the header
- sh (object) - optional - (default is ActiveSheet) = the worksheet object
- HeaderRow (Long) - optional - (default is Row 1) = the row of your headers

to use

VBA Code:
Sub TestIt()
Dim NMcolID As Long
NMcolID = GetColumn("ID", S1, 10)

MsgBox NMcolID
 End Sub

Hopefully, this will simply things for you

Dave
 
Upvote 0
That's a shame - make life so much easier

If you just want to get the column number for any worksheet heading then try this update to your approach & see if will work for you

Place in STANDARD module
VBA Code:
Function GetColumn(ByVal HeaderName As String, Optional ByVal sh As Object, Optional ByVal HeaderRow As Long = 1) As Long
Dim HeaderArr As Variant, m As Variant
If sh Is Nothing Then Set sh = ActiveSheet
HeaderArr = sh.Rows(HeaderRow).Value2
m = Application.Match(HeaderName, HeaderArr, 0)
GetColumn = IIf(IsError(m), 1, CLng(m))
End Function

Function has three parameters

- HeaderName (string) = the name of the header
- sh (object) - optional - (default is ActiveSheet) = the worksheet object
- HeaderRow (Long) - optional - (default is Row 1) = the row of your headers

to use

VBA Code:
Sub TestIt()
Dim NMcolID As Long
NMcolID = GetColumn("ID", S1, 10)

MsgBox NMcolID
 End Sub

Hopefully, this will simply things for you

Dave
if I use this in every sub and I later change the "ID" to say "Client ID" I would need to change it everywhere and the same issue would actually be with tables, What I wrote in the last method I would have this benefit having all header names in 1 place And I'd only need to change there
 
Upvote 0
I found that dynamic named ranges slows down extremely.
I wasn't suggesting a dynamic range.
Say, at the moment the header you're talking about is in D2. Create a named range, say, myRange that refers to D2. Its column would be 4:
VBA Code:
Debug.Print Range("myRange").Column 'returns 4
Now, try selecting column A and insert a column. Its column is now 5.
VBA Code:
Debug.Print Range("myRange").Column 'now returns 5

Also, if you change its value, say from "Names" to "First Name", this won't affect the cell it refers to.
And you can assign Range("myRange").Column to a procedure level variable, for example:
VBA Code:
Sub test()
Dim xCol as Long
xCol = Range("myRange").Column
'.....
 
Upvote 0
What I wrote in the last method I would have this benefit having all header names in 1 place And I'd only need to change there
OK clearly not fully understanding your post & what you are trying to do.

Providing the column code names you have shown (e.g “NMcolID”) are consistent throughout your project, then an approach you could consider would be to use these in a Table (Listobjects) which where you can update your Column Names - this will negate the need to hard code any changes. However, if the function is to be used across different sheets you will still need to pass to it which sheet & header row your code is checking against

See if this helps

Add following table to new worksheet & name the sheet Column Names

14-11-2024.xls
AB
1Column CodeColumn Name
2NMcolIDID
3NMcolSNSurname
4NMcolHOHoliday
Column Names


  • Table is dynamic you can add to your column codes & their column names as required
  • Place updated code in standard module
VBA Code:
Function GetColumn(ByVal ColumnCode As String, Optional ByVal sh As Object, Optional ByVal HeaderRow As Long = 1) As Long
    Dim tblColumnNames      As ListObject
    Dim ColumnName          As String
    Dim ColumnNamesArr      As Variant, HeaderRowArr As Variant, m As Variant
   
    If sh Is Nothing Then Set sh = ActiveSheet
    HeaderRowArr = sh.Rows(HeaderRow).Value2
   
    On Error GoTo myerror
    Set tblColumnNames = ThisWorkbook.Worksheets("Column Names").ListObjects(1)
    ColumnNamesArr = tblColumnNames.DataBodyRange.Value2
    m = Application.Match(ColumnCode, Application.Index(ColumnNamesArr, 0, 1), 0)
    If IsError(m) Then Err.Raise 744, , "Column Code Not Found"
       
    ColumnName = ColumnNamesArr(m, 2)
   
    m = Application.Match(ColumnName, HeaderRowArr, 0)
    If IsError(m) Then Err.Raise 744, , "Column Name Not Found"
   
myerror:
    GetColumn = IIf(IsError(m), 1, CLng(m))
    If Err <> 0 Then MsgBox (Error(Err)), 48, "Error"
End Function

Updated function still has three parameters which you will need to pass

  • Column Code – this is the variable name you use in each of your subs (e.g. “NMcolID”)
  • sh – the worksheet object (default is the activesheet)
  • HeaderRow - (default is Row 1)
Your subs will need to be modified like this

VBA Code:
Dim NMcolID As Long
NMcolID = GetColumn("NMcolID", S1, 10)

If you omit the last two arguments then code will apply to Activesheet Row 1

I have only lighly tested but hopefully, this approach will achieve what you were looking for.

Dave
 
Last edited:
Upvote 0

Forum statistics

Threads
1,223,705
Messages
6,173,985
Members
452,540
Latest member
haasro02

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top