0

I'm having difficulty to have VBA select an entire column by name (can have noncontigous data) after searching for the column.

' Select the first row
Rows("1:1").Select

Selection.Find(What:="LongColumnName", After:=ActiveCell, LookIn:= _
    xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
    xlNext, MatchCase:=False, SearchFormat:=False).Activate
    Selection.End(xlUp).Select

Problem is after finding the cell the selection is still the entire row 1. After I have the selected column I will move it to the front and will do this for several columns. Lastly I will insert columns and do some comparison between the column values.

Thanks

Community
  • 1
  • 1
user9719232
  • 3
  • 1
  • 2

2 Answers2

4

You shouldn't Select and Activate ranges

The process of moving columns can be like this


Option Explicit

Public Sub MoveColumns1()
   Const SDEL = "|||"    'column names cannot contain the delim chars ("|||")
   Const CN = "Col2" & SDEL & "Col1 `!@#$%^&*()_+-={}[];':"""",./<>?"

   Dim ws As Worksheet, cols As Variant, arr As Variant, newStart As Long, cnX As String
   Dim trim1 As String, trim2 As String, i As Long, j As Long, cn1 As String

   Set ws = Sheet1          'Or: Set ws = ThisWorkbook.Worksheets("Sheet1")
   cn1 = "Col3 - Line 1" & Chr(10) & "Col3 - Line 2" & Chr(10) & "Col3 - Line 3"
   cnX = cn1 & SDEL & CN    'Header with multiple lines of text, separated by Chr(10)
   cols = Split(cnX, SDEL)  '0-based array containing names defined in cnX
   arr = ws.Range(ws.Cells(1), ws.Cells(1, ws.Columns.Count).End(xlToLeft)) 'hdr row (1)

   Application.ScreenUpdating = False   'Turn screen Off
   For i = 1 To UBound(arr, 2)          'Iterate all Header cells (in row 1)
      trim1 = Trim$(arr(1, i))          'Trim left/right white-spaces from each Header
      For j = 0 To UBound(cols)         'Iterate each name defined in cnX
         trim2 = Trim$(cols(j))         'Trim left/right white spaces in current cnX
         If Len(trim1) >= Len(trim2) Then       'If Header is longer than current cnX
            If InStrB(1, trim1, trim2) > 0 Then 'If Header contains current cnX
               ws.Cells(i).EntireColumn.Cut         'Copy current cnX column (i)
               ws.Cells(1).Insert Shift:=xlToRight  'Paste column as first (1)

               newStart = Len(cnX) - (InStr(1, cnX, trim2) + Len(trim2) + Len(SDEL) - 1)
               If newStart < 1 Then Exit Sub    'If the cnX list is empty, we are done
               cols = Split(Right(cnX, newStart), SDEL)  'Remove current cnX
               Exit For                         'Done with current cnX
            End If
         End If
      Next
   Next
   Application.ScreenUpdating = False   'Turn screen back On
End Sub

Modify the constant CN at the top to include all columns to be moved


Before

Before

After

After


Note: If a column name contains multiple lines of text, you can add just the first line to the constant CN. You can also define each individual column name with multiple lines of text as I defined it in variable cn1

This also works:

Public Sub MoveColumns2()
   Const SDEL = "|||"    'column names cannot contain the delim chars ("|||")
   Const CN = "Col3 - Line 1" & SDEL & "Col2" & SDEL & "Col1 `!@#$%^&*()_+-={}[];':"""",./<>?"

   Dim ws As Worksheet, cols As Variant, arr As Variant, newStart As Long, cnX As String
   Dim trim1 As String, trim2 As String, i As Long, j As Long, cn1 As String

   Set ws = Sheet1          'Or: Set ws = ThisWorkbook.Worksheets("Sheet1")
   cnX = CN                 'Header with multiple lines of text, separated by Chr(10)
   cols = Split(cnX, SDEL)  '0-based array containing names defined in cnX
   arr = ws.Range(ws.Cells(1), ws.Cells(1, ws.Columns.Count).End(xlToLeft)) 'hdr row (1)

   Application.ScreenUpdating = False   'Turn screen Off
   For i = 1 To UBound(arr, 2)          'Iterate all Header cells (in row 1)
      trim1 = Trim$(arr(1, i))          'Trim left/right white-spaces from each Header
      For j = 0 To UBound(cols)         'Iterate each name defined in cnX
         trim2 = Trim$(cols(j))         'Trim left/right white spaces in current cnX
         If Len(trim1) >= Len(trim2) Then       'If Header is longer than current cnX
            If InStrB(1, trim1, trim2) > 0 Then 'If Header contains current cnX
               ws.Cells(i).EntireColumn.Cut         'Copy current cnX column (i)
               ws.Cells(1).Insert Shift:=xlToRight  'Paste column as first (1)

               newStart = Len(cnX) - (InStr(1, cnX, trim2) + Len(trim2) + Len(SDEL) - 1)
               If newStart < 1 Then Exit Sub    'If the cnX list is empty, we are done
               cols = Split(Right(cnX, newStart), SDEL)  'Remove current cnX
               Exit For                         'Done with current cnX
            End If
         End If
      Next
   Next
   Application.ScreenUpdating = False   'Turn screen back On
End Sub
paul bica
  • 10,557
  • 4
  • 23
  • 42
  • Hi Paul, Thanks a lot for giving more clarify and more efficient suggestions. I have a large number of columns that I want to move and there are special characters like "=" and ":" contained within the column name. It's not working for me resulting in several compile errors. Any suggestions? I tried putting quotation around each column name and adding a "-" to extend the column list across multiple lines. I'm doing exact match so I also modified the search from LookAt:=xlpart to LookAt:=xlWhole – user9719232 May 06 '18 at 19:32
  • @user9719232 - I customized the search for column names to find all columns containing special characters – paul bica May 06 '18 at 21:58
0

Given your description, the code you passed would work if you changed Activate for Select and xlUp for xlDown. So it would look like

Rows("1:1").Select

Selection.Find(What:="LongColumnName", After:=ActiveCell, LookIn:= _
xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
xlNext, MatchCase:=False, SearchFormat:=False).Select
Selection.End(xlDown).Select

However, if you have empty rows in that column that could generate some problems (since in your description you stated you would want to select the entire column). So I would go for the following

Rows("1:1").Select

Selection.Find(What:="LongColumnName", After:=ActiveCell, LookIn:= _
xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
xlNext, MatchCase:=False, SearchFormat:=False).EntireColumn.Select
LFB
  • 676
  • 2
  • 8
  • 20
  • Thanks Luciano! I really appreciate the help. I'll go back to see where my understanding can be improved now. – user9719232 Apr 30 '18 at 02:33
  • No problem!! But indeed you should avoid selecting the objects in order to do stuff to them. Depending on what you are doing you'll find faster ways to do what you need – LFB Apr 30 '18 at 10:09