9

I'm attempting to create a macro to do the following:

  1. Search a spreadsheet column header by name.
  2. Select all data from the selected column, except column header.
  3. Take Number Stored As Text & Convert to Number.
  • Converting to Number to use for VLookup.

For Example:

Visual Spreadsheet Example:

enter image description here

I've discovered the following code online:

With ActiveSheet.UsedRange

Set c = .Find("Employee ID", LookIn:=xlValues)

If Not c Is Nothing Then

    ActiveSheet.Range(c.Address).Offset(1, 0).Select
End If

End With

However, I'm still experiencing some issues.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
Laissez Faire
  • 101
  • 1
  • 1
  • 6

5 Answers5

10

I just stumbled upon this, for me the answer was pretty straightforward, in any case If you're dealing with a ListObject then this is the way to go:

YOURLISTOBJECT.HeaderRowRange.Cells.Find("A_VALUE").Column
Carlos_E.
  • 671
  • 8
  • 14
7

It is good to avoid looping through all cells. If the data set grows the macro can become too slow. Using special cells and paste special operation of multiplying by 1 is an efficient way of accomplishing the task.

This works...

Dim SelRange As Range
Dim ColNum As Integer
Dim CWS As Worksheet, TmpWS As Worksheet

'Find the column number where the column header is
Set CWS = ActiveSheet
ColNum = Application.WorksheetFunction.Match("Employee ID", CWS.Rows(1), 0)

'Set the column range to work with
Set SelRange = CWS.Columns(ColNum)

'Add a worksheet to put '1' onto the clipboard, ensures no issues on activesheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False

    Set TmpWS = ThisWorkbook.Worksheets.Add
    With TmpWS
        .Cells(1, 1) = 1
        .Cells(1, 1).Copy
    End With

    'Select none blank cells using special cells...much faster than looping through all cells
    Set SelRange = SelRange.SpecialCells(xlCellTypeConstants, 23)
    SelRange.PasteSpecial Paste:=xlPasteAll, Operation:=xlMultiply
    TmpWS.Delete
    CWS.Select

Application.DisplayAlerts = True
Application.ScreenUpdating = True
dra_red
  • 432
  • 1
  • 3
  • 10
  • Hi @dra_red, Thank you for your assistance. I believe this converts the data into number correctly. Unfortunately the column header changes to a white background with unbolded font. Which isn't a big deal. I guess I could repaint over it. As far as logic, I used F8 to go step by step through the code. Not sure why a Temporary Sheet is created and what it does. If you could explain, I'd be very grateful. Just for my own understanding. Again, thank you for helping. – Laissez Faire Jun 14 '16 at 14:26
  • Hi @Laissez, To use 'pastespecial' with the 'multiply' operation you need to copy the value you are going to multiply by first. There are a few ways to go about this but to avoid various complications, I put the value on a new sheet before copying it. After the value is copied and the operation is completed, the sheet is deleted. This operation should not impact on formatting in the way you described. I can't say why that happened without looking at the workbook. The good thing about this approach is its efficiency. It pays off if you ever need to operate on a larger data set... – dra_red Jun 16 '16 at 03:53
  • Is it possible to do this, but search the first 20 rows for the "Employee ID" to allow for the header row moving? – Al Grant Apr 13 '21 at 21:25
2

Try this out. Simply add all the column header names you want to find into the collection. I'm assuming you don't have more than 200 columns, if you do simply update the for i = 1 to 200 section to a larger number.

Public Sub FindAndConvert()
    Dim i           As Integer
    Dim lastRow     As Long
    Dim myRng       As Range
    Dim mycell      As Range
    Dim MyColl      As Collection
    Dim myIterator  As Variant

    Set MyColl = New Collection

    MyColl.Add "Some Value"
    MyColl.Add "Another Value"

    lastRow = ActiveSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

    For i = 1 To 200
        For Each myIterator In MyColl
            If Cells(1, i) = myIterator Then
                Set myRng = Range(Cells(2, i), Cells(lastRow, i))
                For Each mycell In myRng
                    mycell.Value = Val(mycell.Value)
                Next
            End If
        Next
    Next
End Sub
Ryan Wildry
  • 5,612
  • 1
  • 15
  • 35
  • Hi @Ryan Wildry, Thank you for your help. This solution tends to help the most. I didn't do a step by step process since it was a long loop. But, it accomplishes the task. Thank you for your help. – Laissez Faire Jun 14 '16 at 14:42
1

Ok, here's a brief way of achieving your goal. First, locate the column that holds the Employee IDs. Then simply set the entire Column to be formatted as Number instead of Text?

With Worksheets(1)  ' Change this sheet to the one you are using if not the first sheet
    Set c = .Find("Employee ID", LookIn:=xlValues)

    If Not c Is Nothing Then
        ' The column we want is c's Column.
        Columns(c.Column).NumberFormat = 0
    End If
End With
Dave
  • 4,328
  • 2
  • 24
  • 33
  • This just changes the format, not the value. For example, you can't add the numbers together. – Ryan Wildry Jun 07 '16 at 19:34
  • It's an Employee ID - why on earth would you ever want to add them together? – Dave Jun 07 '16 at 19:38
  • 1
    Your solution doesn't address the ask. Specifically asked for convert. There may be other columns that are going to be converted where this is more sensible. Not for us to say. – Ryan Wildry Jun 07 '16 at 19:58
  • Hello All, Thank you for your quick replies. I didn't think anyone would be able to respond so quickly. My purpose later on is to use them for VLookup. If the IDs are not in number format for my specific purpose the VLookup will not work properly. As far as this code, thank you so much for your help, unfortunately I could not get this code to run properly. : ( – Laissez Faire Jun 14 '16 at 14:14
0

Add a dim for the range that you want:

Dim MyRng, RngStart, RngEnd as Range

Then change:

ActiveSheet.Range(c.Address).Offset(1, 0).Select

to the below so that all data in that column is found.

set RngStart = ActiveSheet.Cells(1, c.column)
set RngEnd = ActiveSheet.Cells(rows.count, c.column).end(xlup)
set MyRng = ActiveSheet.Range(RngStart & ":" & RngEnd)

Now you can play about with the data. If you want to paste this somewhere which is formatted as number:

MyRng.copy
Sheets("Wherever").Range("Wherever").pastespecial xlvalues

If you want to change the format of the cells you have now found (How to format column to number format in Excel sheet?) that is whole number format, if you want decimal points then use "number" instead of "0":

MyRng.NumberFormat = "0"

or the new destination:

Sheets("Wherever").Range("Wherever").NumberFormat = "0"

General formatting which matches exactly the convert to number function:

MyRng.NumberFormat = "General"
MyRng.Value = MyRng.Value
Community
  • 1
  • 1
Glitch_Doctor
  • 2,994
  • 3
  • 16
  • 30
  • This just changes the format, not the value. For example, you can't add the numbers together. – Ryan Wildry Jun 07 '16 at 19:33
  • I'm sorry, what exactly are you trying to do then? Add up all the staff ID's? Count how many times a staff id appears in the list of data? Count the staff ID's? Going to need more of a breakdown for what you are trying to do before I can help out... – Glitch_Doctor Jun 07 '16 at 19:37
  • I didn't ask the question. It's clear from the ask they want it converted to a number, probably to do some sort roll up on a column somewhere in there. – Ryan Wildry Jun 07 '16 at 19:56
  • But convert to a number is exactly what the above is doing? – Glitch_Doctor Jun 07 '16 at 20:02
  • Also once you have the range you can do all sorts with it. `Dim Total as long for each cell in MyRng total = total + cell.value next cell` just as one example. – Glitch_Doctor Jun 07 '16 at 20:16
  • It doesn't, it is still text. – Ryan Wildry Jun 07 '16 at 20:35