VBA: Retrieve cell value from each row in Range.Area - vba

The main goal is: Retrieve specific cell values from each row in a filtered table by using column reference name.
So far, I have the following code
Dim table As listObject
Dim columns As ListColumns
Dim row As ListRow
Dim rnData As range
Dim rngArea As range
Set table = Sheets(sheetName).ListObjects(TableName)
Set columns = table.ListColumns
Set rnData = ThisWorkbook.Worksheets(sheetName).ListObjects(TableName).range
'Notice that sheetName and TableName are function arguments. No need to pay attention. Consider any string values.
'Filter my table
table.range.AutoFilter Field:=7, Criteria1:=Array("filtervalue1", "filtervalue2"), Operator:=xlFilterValues
'Set the filtered table in a new Range object
Set rnData = ThisWorkbook.Worksheets(sheetName).ListObjects(TableName).range
'Count all rows of my filtered table
With rnData
For Each rngArea In .SpecialCells(xlCellTypeVisible).Areas
lCount = lCount + rngArea.Rows.Count
Next
End with
Now I want to loop my filtered table (my "rnData" range) and I want to get the cell value for each row in those Range.Areas.
I was thinking something like this, but i'm having difficulties with VBA to do this:
For iRowNo = 2 To (lCount - 1) 'Start at 2 because 1 is the table header
'This does not work once it gets another row from the entire table. Not the filtered one. Help here!
Set row = table.ListRows(iRowNo)
'Something close to this - Help Here!
Set row = rnData.SpecialCells(xlCellTypeVisible).Areas
''Would like to have the code like this to get the values
cell1Value= row.range(1, columns("My Column Header 1").Index).value
cell2Value= row.range(1, columns("My Column Header 2").Index).Value
Next iRowNo
Let me know if there are different solutions than this.

Following the #DirkReichel answer
Here is the code that worked for me:
Dim table As listObject
Dim columns As ListColumns
Dim row As ListRow
Dim rnData As range
Dim rngArea As range
Set table = Sheets(sheetName).ListObjects(TableName)
Set columns = table.ListColumns
Set rnData = ThisWorkbook.Worksheets(sheetName).ListObjects(TableName).range
'Notice that sheetName and TableName are function arguments. No need to pay attention. Consider any string values.
'Filter my table
table.range.AutoFilter Field:=7, Criteria1:=Array("filtervalue1", "filtervalue2"), Operator:=xlFilterValues
'Set the filtered table in a new Range object
Set rnData = ThisWorkbook.Worksheets(sheetName).ListObjects(TableName).range
'Get values for each row
With rnData
For Each rngArea In .SpecialCells(xlCellTypeVisible).Areas
For Each row In rngArea.Rows
cell1Value= row.range(1, columns("My Column Header 1").Index).value
cell2Value= row.range(1, columns("My Column Header 2").Index).Value
Next
'lCount = lCount + rngArea.Rows.Count 'Removed this.
Next
End with
'Also no need the second part of code with the For..Next loop.

I think you're indirectly trying to create an array which is not something that can be easily explained a single post, but here's some code to get you started.
I'm going to assume that your set rnData range is correct. From there, it's probably easiest to just loop through all cells in range. You could write code more precise than below, but this should help you see a couple ideas besides what you're trying.
Most important I think you're looking for a method to create an array. I hope this helps.
Sub testCoutinho()
Dim Rcell As Range
Dim rnData As Range 'you'll have to set this up...
Dim YesLetsDoAnArray As Boolean: YesLetsDoAnArray = False 'or change to false to just make a new sheet with values
If YesLetsDoAnArray Then
ReDim This_is_your_Array(0) As Variant 'Create Array
Dim x As Integer
Else
'putting values on a new worksheet in file
Dim CleanWS As Worksheet: Set CleanWS = ThisWorkbook.Sheets.Add
End If
For Each Rcell In rnData.Cells
If Rcell.EntireRow.Hidden = False Then
If YesLetsDoAnArray Then
ReDim Preserve This_is_your_Array(x)
This_is_your_Array(x) = Rcell.Value
x = x + 1
Else
CleanWS.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Value = Rcell.Value
End If
End If
Next Rcell
'If you used an array, you'll know have variable(s) that contain all your data.
'your first one is This This_Is_Your_Array(0), followed by This_Is_Your_Array(1)... etc.
'you can play around. this will print them all.
If YesLetsDoAnArray Then
Dim i As Integer
For i = 0 To x - 1
Debug.Print This_is_your_Array(i)
Next i
End If
End Sub

Related

List table name AND cell in last row and column

I am looking to list all table names in a sheet, together with the table's corresponding cell in the last row and column. The below code finds the table names in sheet "A1.6Laster" (Except table "Lastkategori") and then lists them in sheet "A1.6.5Lastkombinationer".
Since I can add/delete tables i sheet "A1.6Laster", the list is first deleted/cleared.
In other words; the below code work fine listing the names of the tables, but in the column next to the name list I want each table's corresponding cell in the last row and column to be listed as well. Do I need to add some code in the For Each loop?
Any input is welcome, and please ask if you need further information!
Sub Laster()
Dim tbl As ListObject
Dim wsSummary As Worksheet
Dim ws As Worksheet
Dim lRow As Long
Dim SearchText As String
Dim GCell As Range
SearchText = "Laster"
Set GCell = Worksheets("A1.6.5Lastkombinationer").Cells.Find(SearchText).Offset(0)
Set wsSummary = Worksheets("A1.6.5Lastkombinationer")
Set ws = Worksheets("A1.6Laster")
With Worksheets("A1.6.5Lastkombinationer").ListObjects("Laster").DataBodyRange
If .Rows.Count > 1 Then
.Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count).Rows.Delete
End If
End With
Worksheets("A1.6.5Lastkombinationer").ListObjects("Laster").DataBodyRange.Rows(1).ClearContents
lRow = GCell.Row
For Each tbl In Worksheets("A1.6Laster").ListObjects
If tbl.Name <> "Lastkategori" Then
lRow = lRow + 1
With wsSummary
.Cells(lRow, "A") = tbl.Name
End With
End If
Next tbl
ws.ListObjects("Lastkategori").ListColumns(1).DataBodyRange.Copy
wsSummary.ListObjects("Laster").DataBodyRange(1, 1).End(xlDown).Offset(1).PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
I am assuming when you say last row and column means the bottom right hand corner cell of each table.
Add the following snippet within With wsWsummary ... End With. What it does is it takes the range of cells for each table's data range and gets the last row's last column and spits out the data in that cell into the column next to the table's name.
Dim r As Range
Dim last As Range
Set r = tbl.DataBodyRange
Set last = r.Cells(r.Rows.Count, r.Columns.Count)
ws.Cells(lRow, "B").Value = last

Find Last cell from Range VBA

How to find location of last cell from defined Range? Cell does not have to contain any data but must be most right and most down located cell from certain Range.
Set rngOrigin = wksOrigin.Cells(IntFirstRow, IntFirstColumn).CurrentRegion
I wish to receive
Cells(i,j)
Perhaps this is what you want:
Dim rngLastCell As Range
Set rngLastCell = rngOrigin(rngOrigin.Count)
maybe you're after this:
'absolute indexes from cell A1
With rngOrigin
i = .Rows(.Rows.count).row
j = .Columns(.Columns.count).Column
End With
'relative indexes from rngOrigin upleftmost cell
With rngOrigin
i = .Rows(.Rows.count).row - .Rows(1).row + 1
j = .Columns(.Columns.count).Column - .Columns(1).Column + 1
End With
I handled it in below code but your remarks were helpful. Thank you.
intLastRow = rngOrigin.Cells(1, 1).Row + rngOrigin.Rows.Count - 1
intLastCol = rngOrigin.Cells(1, 1).Column + rngOrigin.Columns.Count - 1
The answers given by others mostly work, but not if the region is a union of non-contiguous cells. Here is a version that works consistently for single and multi-area regions, contiguous and non-contiguous.
Function LastCellOfRange(rng As Excel.Range) As Excel.Range
Dim area As Excel.Range
Dim rowNum As Long
Dim maxRow As Long
Dim colNum As Long
Dim maxCol As Long
Dim areaIdx As Integer
Set LastCellOfRange = Nothing
maxRow = 0
maxCol = 0
For areaIdx = 1 To rng.Areas.Count
Set area = rng.Areas(areaIdx)
rowNum = area.Cells(area.Cells.Count).row
If (rowNum > maxRow) Then
maxRow = rowNum
End If
colNum = area.Cells(area.Cells.Count).Column
If (colNum > maxCol) Then
maxCol = colNum
End If
Next areaIdx
Set LastCellOfRange = rng.Worksheet.Cells(maxRow, maxCol)
Set area = Nothing
End Function
Use this to code find the last cell in a given range
Sub GetLastCellFromRange()
Dim rng As Range
Set rng = Range("$C$10:$E$20")
'Set rng = Range(Selection.Address) ' Use this line to select the range in worksheet
MsgBox "Last Cell of given range is : " & rng.Cells(rng.Rows.Count, rng.Columns.Count).Address
End Sub
I hope it will help you
you could try the following but it relies upon cells always being populated
rngOrigin.End(xlDown).End(xlRight)
or you could use the CurrentRegion and count the rows and columns and use Offset
Alternatively, you could use this construct which works even with ranges based on entire rows or entire columns.
Sub Test()
Dim rngOrigin As Excel.Range
Set rngOrigin = Range("$A$1:$D$6")
Dim rngLast As Excel.Range
Set rngLast = rngOrigin.Cells(rngOrigin.Cells.Count)
Debug.Print rngLast.Address
End Sub
Finally, for ranges with multiple areas you'll have to script against a range's Areas collection ...
Sub Test()
Dim rngOrigin As Excel.Range
Set rngOrigin = Range("$A$1:$D$6,$F$1:$G$6")
Debug.Print rngOrigin.Areas(1).Cells(rngOrigin.Areas(1).Cells.Count).Address
Debug.Print rngOrigin.Areas(2).Cells(rngOrigin.Areas(2).Cells.Count).Address
End Sub
Many answers here will work as long as the given range is continuous. This is what I would use for a range that you are absolutely sure is going to be continuous:
Sub test()
Dim myRng As Range, lastCell As Range
Set myRng = Range("A1:D4")
Set lastCell = myRng.Cells(myRng.Rows.Count, myRng.Columns.Count)
Debug.Print lastCell.Address 'returns $D$4
End Sub
For non-continuous, DB user10082797 gave a great solution, however their function fails when the ranges are positioned diagonal-up (for example, if you pass rng=A3:B4,C1:D2 in you will get D4 as the output which was not part of the original range.)
So the question becomes, what is the last cell in the range A3:B4,C1:D2? Is it B4 or D2? That's a decision for the programmer. Here is a function I wrote with the help of DB user10082797's function:
Function LastCellOfRange(rng As Range, Optional returnLastRow As Boolean = True) As Range
'returns the last cell in #rng.
'if #returnLastRow is TRUE, then the output will always be in the right most cell of the last row of #rng
'if #returnLastRow is FALSE, then the output will always be in the bottom most cell of the last column of #rng
'(#returnLastRow only matters for non-contiguous ranges under certain circumstances.)
'initialize variables
Dim area As Range, areaIdx As Long
Dim lastCellInArea As Range
'loop thru each area in the selection
For areaIdx = 1 To rng.Areas.Count
Set area = rng.Areas(areaIdx) 'get next area
Set lastCellInArea = area.Cells(area.Rows.Count, area.Columns.Count) 'get the last cell in the area
'if:
' the return is empty
' OR if the last row needs to be returned and this row is larger than the last area's
' OR if the last row needs to be returned and this row is the same as the last area's but has a larger column
' OR if the last column needs to be returned and this column is larger than the last area's
' OR if the last column needs to be returned and this column is the same as the last area's but has a larger row
'THEN:
' make this cell the return range
If LastCellOfRange Is Nothing Then
Set LastCellOfRange = lastCellInArea '(must be seperate from the other statment when its not set to anything)
ElseIf _
returnLastRow = True And lastCellInArea.Row > LastCellOfRange.Row _
Or returnLastRow = True And lastCellInArea.Row = LastCellOfRange.Row And lastCellInArea.Column > LastCellOfRange.Column _
Or returnLastRow = False And lastCellInArea.Column > LastCellOfRange.Column _
Or returnLastRow = False And lastCellInArea.Column = LastCellOfRange.Column And lastCellInArea.Row > LastCellOfRange.Row _
Then
Set LastCellOfRange = lastCellInArea
End If
Next areaIdx
End Function
You can use the function like this:
Sub test()
Dim myRng As Range
Set myRng = Range("A3:B4,C1:D2")
Debug.Print LastCellOfRange(myRng).Address 'returns $B$4
Debug.Print LastCellOfRange(myRng, False).Address 'returns $D$2
End Sub
In your case, since you want to find the cell to the most right and down in your wksOrigin (defined as Worksheet), you could use the SpecialCells(xlCellTypeLastCell) to get the last cell Row and Column.
i = wksOrigin.Cells.SpecialCells(xlCellTypeLastCell).Row ' <-- get last row number
j = wksOrigin.Cells.SpecialCells(xlCellTypeLastCell).Column ' <-- get last column number
If you want to debug your result, you can add:
MsgBox "Last row at " & i & ", last column at " & j
If you want the absolute last cell of a defined range, regardless of whether it has any content, here is a simple solution
Dim InputRng As Range 'define a range for the test'
Set InputRng = Range("$F$3:$F$15")
MsgBox InputRng(1).Address & ":" & InputRng(InputRng.Cells.Count).Address 'This would output the absolute address of defined range'

Find Column Header By Name And Select All Data Below Column Header (Excel-VBA)

I'm attempting to create a macro to do the following:
Search a spreadsheet column header by name.
Select all data from the selected column, except column header.
Take Number Stored As Text & Convert to Number.
Converting to Number to use for VLookup.
For Example:
Visual Spreadsheet Example:
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.
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
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
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
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
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

Deleting or keeping multiple rows by a specific word content

I'm trying to write a code that either deletes or keeps rows by a specific word input by the end-user.
I've created two button actions:
Sub Button1_Click()
Dim cell As Range
word1 = InputBox("Enter a word by which you want to keep rows", "Enter")
For Each cell In Selection
cell.EntireRow.Hidden = (InStr(1, cell, word1, 1) = 0) 'keep by a word input by the user
Next
End Sub
Sub Button2_Click()
Dim cell As Range
word2 = InputBox("Enter a word by which you want to delete rows", "Enter")
For Each cell In Selection
cell.EntireRow.Hidden = (InStr(1, cell, word2, 1) = 1) 'delete by a word input by the user
Next
End Sub
However, these buttons don't work quite the way I would like them to do.
Problems:
1) I have to specifically select the cells in the column of the text to be searched; if I select the whole block of data,everything will be deleted.
2) Actually, the program would be handier, if it did its magic from the cell J22 onwards (to the right and downwards) until the end of the data is reached, without the need to select anything. What is the best way to do this?
3) If I use these buttons several times sequentially, the rows that I've already deleted keep popping up again. How to make the delete "permanent" each time I use one of these buttons? By changing Hidden to Delete I start to get run-time errors.
When you attempt to delete permanently the macro deletes a row, shifts all of the other rows up one to accomodate and this disrupts the flow of your 'For Each...Next'.
There are a couple of ways around this either way it very much changes the shape of your code.
One of them is to add the rows you wish to delete to a union during the loop and then delete the union outside of the loop (example A below). In any case it sounds like you want to specify the range you want this code to work on so I've incorporated that into each example.
Example A
Sub Button1_Click()
Dim endR As Integer, endC As Integer 'depending on size of sheet may need to change to Long
Dim cell As Range, rng As Range, U As Range
Dim ws As Worksheet
Set ws = Sheets(2) ' change accordingly
endR = ws.UsedRange.Rows.Count
endC = ws.UsedRange.Columns.Count
Set rng = Range(ws.Cells(22, 10), ws.Cells(endR, endC)) ' from cell J22 to last used row of the last used column on the right
word1 = InputBox("Enter a word by which you want to keep rows", "Enter")
For Each cell In rng
If InStr(1, cell, word1, 1) = 0 Then
If U Is Nothing Then ' for the first time the code finds a match
Set U = cell.EntireRow ' add row to be deleted to U variable
Else
Set U = Union(U, cell.EntireRow) ' for any subsequent matches, add row to be deleted to Union
End If
End If
Next
U.Delete
End Sub
The other way to do it would be to define the exact ranges you want to work with at the start of your code and then loop backwards through that range using loop control variables instead of for each, that way when you delete a row, the shift up doesn't impact the loop.
Sub Button2_Click()
Dim r As Integer, c As Integer
Dim endR As Integer, endC As Integer
Dim cell As Range, rng As Range
Dim ws As Worksheet
Set ws = Sheets(2) ' change accordingly
endC = ws.UsedRange.Columns.Count
word2 = InputBox("Enter a word by which you want to delete rows", "Enter")
For c = 10 To endC ' start from J and move to the right
endR = ws.UsedRange.Rows.Count ' after each column has been dealt with, re-evaluate the total rows in the worksheet
For r = endR To 22 Step -1 ' start from the last row and work up
If InStr(1, ws.Cells(r, c), word2, 1) = 1 Then
ws.Cells(r, c).EntireRow.Delete
End If
Next r
Next c
End Sub
With your current code, if you select the whole block of data, it checks each cell in that selection individually and acts accordingly. If you have a range selected like A1:J1,000, it will hide every row unless each cell in every row of the selection contains the input word.
Depending on what you exactly want, you could try something Sheets("Sheet1").Cells(Sheets("Sheet1").Rows.count, 10).End(xlUp).Row this returns the rownumber of the last cell in column 10(J), more examples of this in the code below
This is caused by the for loop and the deletion of rows, say For i = 1 To 100 you check cells A1 to A100, if you then delete a row during that loop, the loop will still continue to 100 and not end at 99, the end of the loop is set before the loop starts and does not change during the loop. More information on that and it's solutions here.
General
Avoid the .Select/.Activate methods and .Selection property, it is a source of many bugs.
Declare all your variables, use Option Explicit to enforce this.
Here is the refactored code with annotations.
Option Explicit
Sub Button1_Click()
'Keep rows based on input
'Declaration of variables
Dim i As Long
Dim strFilterWord As String
Dim rngCell As Range
Dim rngToDelete As Range, rngRow As Range
Dim arrRow() As Variant, arrTmp() As Variant
'Setting the filter word
strFilterWord = InputBox("Enter a word by which you want to keep rows", "Enter")
With ThisWorkbook.Worksheets("Sheet1") 'Replace "Sheet1" with the actual name of your sheet.
'Setting up for loop, currently range to loop over is J22:J(lastrow with data)
For Each rngCell In .Range(.Cells(22, 10), .Cells(Rows.Count, 10).End(xlUp))
'All values of the current row are combined into an array
'Determining and setting the range of the current row
Set rngRow = rngCell.Resize(1, 3)
'Populate a tmp array with the row range values
arrTmp = rngRow
'To use the array, it needs to be 1D, currently it is 2D, section below accomplishes this
'resize the final array
ReDim arrRow(LBound(arrTmp, 2) To UBound(arrTmp, 2))
'Copy values to final array
For i = LBound(arrTmp, 2) To UBound(arrTmp, 2)
arrRow(i) = arrTmp(1, i)
Next i
'the final array is combined to a single string value with " "(spaces) between each array element
'if the filterword is not found in the string Instr returns a 0
'If the filterword is found in the string InStr returns a number corresponding to the start position.
If InStr(1, Join(arrRow, " "), strFilterWord, vbTextCompare) = 0 Then
'Test to see if the range to delete is empty or not
If rngToDelete Is Nothing Then
'If the range is empty, it is set to the first row to delete.
Set rngToDelete = rngCell.EntireRow
Else
'if the range is not empty, the row to delete is added to the range.
Set rngToDelete = Union(rngToDelete, rngCell.EntireRow)
End If
End If
Next rngCell
'After all cells are looped over, the rows to delete are deleted in one go
If Not rngToDelete Is Nothing Then rngToDelete.Delete
End With
End Sub
Sub Button2_Click()
'Keep rows based on input
'Declaration of variables
Dim i As Long
Dim strFilterWord As String
Dim rngCell As Range
Dim rngToDelete As Range, rngRow As Range
Dim arrRow() As Variant, arrTmp() As Variant
'Setting the filter word
strFilterWord = InputBox("Enter a word by which you want to delete rows", "Enter")
With ThisWorkbook.Worksheets("Sheet1") 'Replace "Sheet1" with the actual name of your sheet.
'Setting up for loop, currently range to loop over is J22:J(lastrow with data)
For Each rngCell In .Range(.Cells(22, 10), .Cells(Rows.Count, 10).End(xlUp))
'All values of the current row are combined into an array
'Determining and setting the range of the current row
Set rngRow = rngCell.Resize(1, 3)
'Populate a tmp array with the row range values
arrTmp = rngRow
'To use the array, it needs to be 1D, currently it is 2D, section below accomplishes this
'resize the final array
ReDim arrRow(LBound(arrTmp, 2) To UBound(arrTmp, 2))
'Copy values to final array
For i = LBound(arrTmp, 2) To UBound(arrTmp, 2)
arrRow(i) = arrTmp(1, i)
Next i
'the final array is combined to a single string value with " "(spaces) between each array element
'if the filterword is not found in the string Instr returns a 0
'If the filterword is found in the string InStr returns a number corresponding to the start position.
If InStr(1, Join(arrRow, " "), strFilterWord, vbTextCompare) > 0 Then
'Test to see if the range to delete is empty or not
If rngToDelete Is Nothing Then
'If the range is empty, it is set to the first row to delete.
Set rngToDelete = rngCell.EntireRow
Else
'if the range is not empty, the row to delete is added to the range.
Set rngToDelete = Union(rngToDelete, rngCell.EntireRow)
End If
End If
Next rngCell
'After all cells are looped over, the rows to delete are deleted in one go
If Not rngToDelete Is Nothing Then rngToDelete.Delete
End With
End Sub
This should do the trick
Option Explicit
Sub DeletingRowContainingSpecificText()
Dim DataWorkSheet As Worksheet
'Change "ThisWorkBook" an "Sheet1" as you require
Set DataWorkSheet = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long
Dim LastColumn As Long
With DataWorkSheet.UsedRange
LastRow = .Rows(.Rows.Count).Row
LastColumn = Columns(.Columns.Count).Column
End With
Dim word1 As String
word1 = InputBox("Enter a word by which you want to keep rows", "Enter")
Dim RowRange As Range
Dim RowReference As Long
Dim RowContent As String
Dim WordFound As Variant
'When ever you are deleting you need to start at the end and work your way back
'Otherwise the row after the row you deleted becomes the current row
For RowReference = LastRow To 22 Step -1
'Setting the Row Range from Column J to the end for a specific row
Set RowRange = ThisWorkbook.Worksheets("Sheet1").Range(Cells(RowReference, "J"), Cells(RowReference, LastColumn))
Set WordFound = RowRange.Find(What:=word1, LookIn:=xlValues)
If Not WordFound Is Nothing Then
'Choose if you want to delete or hidden
RowRange.EntireRow.Hidden = True
RowRange.EntireRow.Delete
End If
Next RowReference
End Sub
Just paste the Sub Content into your Button1_Click Sub. Otherwise paste this into your WorkBook Module and then test if it is working first.
I did test it and it worked for me.
NB when working with Deleting Rows or Columns always start at the end of the list and work your way to the beginning, this way the reference doesn't get messed up.
the problem resides in using Selection. You should avoid it at all costs!
If the data always is in the same region, this becomes quite simple. Try something like:
Sub Button1_Click()
Dim cell As Range
Dim rData as Range
'Assigns the range for J22 and adjacent rows and columns
Set rData = ActiveSheet.Range("J22").CurrentRegion
word1 = InputBox("Enter a word by which you want to keep rows", "Enter")
For Each cell In rData
If (InStr(1, cell, word1, 1) = 0) then cell.EntireRow.Delete
Next cell
End Sub
As you are not using Selection anymore, your 3 points get solved

Selecting non-blank cells in Excel with VBA

I'm just beginning to dive into VBA and I've hit a bit of a roadblock.
I have a sheet with 50+ columns, 900+ rows of data. I need to reformat about 10 of those columns and stick them in a new workbook.
How do I programmatically select every non-blank cell in a column of book1, run it through some functions, and drop the results in book2?
I know I'm am very late on this, but here some usefull samples:
'select the used cells in column 3 of worksheet wks
wks.columns(3).SpecialCells(xlCellTypeConstants).Select
or
'change all formulas in col 3 to values
with sheet1.columns(3).SpecialCells(xlCellTypeFormulas)
.value = .value
end with
To find the last used row in column, never rely on LastCell, which is unreliable (it is not reset after deleting data). Instead, I use someting like
lngLast = cells(rows.count,3).end(xlUp).row
The following VBA code should get you started. It will copy all of the data in the original workbook to a new workbook, but it will have added 1 to each value, and all blank cells will have been ignored.
Option Explicit
Public Sub exportDataToNewBook()
Dim rowIndex As Integer
Dim colIndex As Integer
Dim dataRange As Range
Dim thisBook As Workbook
Dim newBook As Workbook
Dim newRow As Integer
Dim temp
'// set your data range here
Set dataRange = Sheet1.Range("A1:B100")
'// create a new workbook
Set newBook = Excel.Workbooks.Add
'// loop through the data in book1, one column at a time
For colIndex = 1 To dataRange.Columns.Count
newRow = 0
For rowIndex = 1 To dataRange.Rows.Count
With dataRange.Cells(rowIndex, colIndex)
'// ignore empty cells
If .value <> "" Then
newRow = newRow + 1
temp = doSomethingWith(.value)
newBook.ActiveSheet.Cells(newRow, colIndex).value = temp
End If
End With
Next rowIndex
Next colIndex
End Sub
Private Function doSomethingWith(aValue)
'// This is where you would compute a different value
'// for use in the new workbook
'// In this example, I simply add one to it.
aValue = aValue + 1
doSomethingWith = aValue
End Function
If you are looking for the last row of a column, use:
Sub SelectFirstColumn()
SelectEntireColumn (1)
End Sub
Sub SelectSecondColumn()
SelectEntireColumn (2)
End Sub
Sub SelectEntireColumn(columnNumber)
Dim LastRow
Sheets("sheet1").Select
LastRow = ActiveSheet.Columns(columnNumber).SpecialCells(xlLastCell).Row
ActiveSheet.Range(Cells(1, columnNumber), Cells(LastRow, columnNumber)).Select
End Sub
Other commands you will need to get familiar with are copy and paste commands:
Sub CopyOneToTwo()
SelectEntireColumn (1)
Selection.Copy
Sheets("sheet1").Select
ActiveSheet.Range("B1").PasteSpecial Paste:=xlPasteValues
End Sub
Finally, you can reference worksheets in other workbooks by using the following syntax:
Dim book2
Set book2 = Workbooks.Open("C:\book2.xls")
book2.Worksheets("sheet1")
For me the best way to proceed was to:
Create a new Excel Table
AutoFilter it by the parameter Criterial:="<>"
An example of the code would be:
Sub ExampleFilterCol()
' Create a Table
Dim ws As Worksheet
Dim rg As Range
Set ws = ActiveSheet
Set rg = ws.Range("A1").CurrentRegion
ws.ListObjects.Add(xlSrcRange, rg, , xlYes).Name = "myNonRepeatedTableName"
' Filter the created table
Dim Io As ListObject
Dim iCol As Long
' Set reference to the first Table on the sheet
' That should be the recently created one
Set lo = Sheets("Totalinfo").ListObjects(1)
' Set filter field
iCol = lo.ListColumns("yourColumnNameToFilter").Index
' Non-blank cells – use NOT operator <>
lo.Range.AutoFilter Field:=iCol, Criteria1:="<>"
End Sub
This might be completely off base, but can't you just copy the whole column into a new spreadsheet and then sort the column? I'm assuming that you don't need to maintain the order integrity.