2

I'm really new to VBA and have been working section by section on a number of pieces of code to format a worksheet (I've been doing it piece by piece so that I understand how each works, and using a final macro to Call all the macros into one long process).

Issue is sometimes the worksheets I work with are not exported with columns in the same order from month to month (out of my control), thus to autosum a particular column I have to Find the column header, then autosum that column, but this makes the column letter(or number) completely variable. I know how to work with rows as variables, but I'm stuck on column. I've been scouring forums to try and find a concise explanation, but to no avail, yet.

This code DOES work for column Y specifically, but I'm trying to figure out how to get it to use a variable for the column. For example, I'm using a separate Macro called "FindInvoiceColumn" to select the 1st cell in the column that contains the string "invoice_amount", then I'd like to use something like I wrote below to set "ColumnAddress" as the column value of that cell. As far as I know .Column returns the column number, which is fine, but I'm assuming I'd have to use with Cells() instead of Range(), I just don't know how to get here.

(Part of the code also shows Adding the word "Total" to the left of the cell containing the autosum value, and making both bold).

Here's what I have so far:

Dim Rng As Range
   Dim c As Range

   Set Rng = Range("Y" & rows.Count).End(xlUp).Offset(1, 0)
   Set c = Range("Y1").End(xlDown).Offset(1, 0)
   c.Formula = "=SUM(" & Rng.Address(False, False) & ")"

   'Selects next empty row of column X to add "Total" label for sum of column Y'
    Range("X" & Cells.rows.Count).End(xlUp).Offset(1, 0).Select
   ActiveCell.FormulaR1C1 = "Total"

   'Bolds Total and the Sum of invoices'
   Range("X" & Cells.rows.Count).End(xlUp).Select
   Selection.Font.Bold = True
   Range("Y" & Cells.rows.Count).End(xlUp).Select
   Selection.Font.Bold = True```




'The below is what I'd like to use to find the dynamic value of the column.'

'Finds cell in row 1 that contains column header "invoice_amount" and selects it'
 Call FindInvoiceColumn

'Dim ColumnAddress As Integer
 ColumnAddress = ActiveCell.Column
Kaz
  • 23
  • 2

2 Answers2

1

You can use .Address to get a column reference, such that:

Sub test()
    Dim varCol As String
    varCol = Columns(ActiveCell.Column).Address
    Debug.Print varCol 'OUTPUTS $A:$A when I had cells(1,1) selected
End Sub

In the above example, I chose a single cell to A) find it's column reference, via .Column, and B) found the .address of said column.


You could also perform the sum on a defined range using .cells() notation, rather than .range() notation.

Sub test2()
    Dim rng As Range
    Set rng = Range(Cells(1, 1), Cells(2, 1))
    Cells(3, 1).Formula = "=sum(" & rng.Address & ")"
End Sub

The above code ouputs: enter image description here


Specific to using the .cells() notation, you can make your column reference a variable, e.g.:

dim r as long, c as long
r = 1
c = 4
debug.print cells(r,c).address `should output $D$1 (untested)

You can choose r or c to fit your needs.


And as always... avoid select/activate where possible!!!



Edit

Adding use of last row via code since comments are terrible:

dim col as long
col = 25 'Y
With sheets("name")
    dim lastRow as long
    lastRow = .cells(.rows.count,col).end(xlup).row
    Dim rng As Range
    Set rng = .Range(.Cells(1, 1), .Cells(lastRow, col))    
end with

This is exactly why I mentioned the specifics abotu the notation after that section (use of r and c as variables).

Cyril
  • 6,448
  • 1
  • 18
  • 31
  • Thank you. I won't be able to use the second method as the number of rows also varies from worksheet to worksheet. Since varCol is Dim as String, this would return the letter form of the column address? If so, how would I implement into ```Set Rng = Range("Y" & rows.Count).End(xlUp).Offset(1, 0) Set c = Range("Y1").End(xlDown).Offset(1, 0) c.Formula = "=SUM(" & Rng.Address(False, False) & ")" ``` – Kaz Jan 08 '20 at 19:06
  • @Kaz i think you would be able to use the second method with Cells. For each sheet/column/etc., you would determine the last row (`lastRow`). `lastRow = .Cells(.Rows.Count, col).End(xlUp).Row` where `col` is your variable column. You can then use `Cells(lastRow,c)` as the end of the range, given example 2. – Cyril Jan 08 '20 at 19:15
  • Ah ok! Thank you for the clarification. Sorry, new at VBA and any kind of code in general. I'm just an EA trying to make my own life easier! – Kaz Jan 08 '20 at 19:22
  • We all start somewhere, @Kaz . If this resolved your issue, let us know (mark as the answer with the green check mark to the left of the post); otherwise, let us know what is still unresolved! – Cyril Jan 09 '20 at 03:09
  • Thank you for your knowledge! – Kaz Jan 14 '20 at 16:02
1

I've used this code to set a column number if your header is in a variable position

Dim F As Object
ColumnAddress = 0
With ActiveSheet.Rows(1)
        Set F = .Find(What:="invoice_amount", LookAt:=xlWhole)
        If F Is Nothing Then
            MsgBox "This is not a proper file"
            ' other code
        Else 
            ColumnAddress = F.Column
        End If
End With

You would then use Cells() in place of range to do further work with the result of ColumnAddress. Also, ColumnAddress should dim as Long, to be accurate.

  • Thank you for this bit of code! However, whenever I get to this portion of the code, do I need to change Rng to something other than Range in order to work with Cells()? (Meaning right now the variable Dim Rng as Range - should it be something else?) Otherwise I keep getting "Run-time error '1004': Application-defined or object defined error" on the line that sets Rng = the first empty row of the column. ```Set Rng = Range("Y" & rows.Count).End(xlUp).Offset(1, 0) Set c = Range("Y1").End(xlDown).Offset(1, 0) c.Formula = "=SUM(" & Rng.Address(False, False) & ")" ``` – Kaz Jan 08 '20 at 19:02
  • `Set Rng = Cells(Rows.Count, ColumnAddress).End(xlUp).Offset(1, 0) Set c = Cells(1, ColumnAddress).End(xlDown).Offset(1, 0)` You'll want anywhere you refer to X (ie, one column to the left), to be cells(row,columnaddress-1) – Tom Kennedy Jan 08 '20 at 21:00
  • ... but as coded, don't Rng and c return the same thing? Are you trying to get c to be a range of cells, like Y2:Y9999 or something, because you'll need further edits to do that. – Tom Kennedy Jan 08 '20 at 21:07