Looping VBA within selected range - vba

I am unable to stop my VBA from looping within the range that I have specified, could someone please check my code and tell me where I am going wrong with it.
Option Explicit
Sub Macro()
Dim oWs As Worksheet
Dim rSearchRng As Range
Dim lEndNum As Long
Dim vFindVar As Variant
Dim loc As Range
Dim LastRow As Long
Dim LRow As Long
Dim Copy As Range
Set oWs = ActiveWorkbook.Worksheets("Sheet1")
LastRow = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
lEndNum = oWs.Range("A2").End(xlDown).Row
Set Copy = oWs.Range("A2" & LRow)
Set rSearchRng = oWs.Range("A2:A" & CStr(lEndNum))
Set loc = rSearchRng.Cells.Find(Range("O2").Value)
If Not loc Is Nothing Then
Do Until loc Is Nothing
loc.Select
Range(ActiveCell.Offset(0, 0), ActiveCell.Offset(0, 12)).Select
Selection.Copy
Sheets("Sheet2").Select
LastRow = Sheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Range("A" & LastRow).Select
Selection.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
ActiveSheet.Paste
Sheets("Sheet1").Select
Application.CutCopyMode = False
Set loc = rSearchRng.FindNext(loc)
Loop
End If
Set loc = Nothing
MsgBox "Complete"
End Sub
Thanks in advance
Aydos

Here is a quote from the help text on FindNext
When the search reaches the end of the specified search range, it wraps around to the beginning of the range. To stop a search when this wraparound occurs, save the address of the first found cell, and then test each successive found-cell address against this saved address.
I think that applies to your situation

it's because Find() method keeps on going inside the range
so you have to stop it when it wraps back to the first found cell by monitoring its address, as follows (along with some other refactoring):
Sub Macro()
Dim oWs As Worksheet
Dim rSearchRng As Range
Dim lEndNum As Long
Dim vFindVar As Variant
Dim loc As Range
Dim LastRow As Long
Dim LRow As Long
Dim Copy As Range
Set oWs = ActiveWorkbook.Worksheets("Sheet1")
LastRow = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
lEndNum = oWs.Range("A2").End(xlDown).Row
Set Copy = oWs.Range("A2" & LRow)
Set rSearchRng = oWs.Range("A2:A" & CStr(lEndNum))
Dim locFirstAddress As String
Set loc = rSearchRng.Cells.Find(Range("O2").value)
If Not loc Is Nothing Then
locFirstAddress = loc.Address
Do
Range(ActiveCell.Offset(0, 0), ActiveCell.Offset(0, 12)).Copy
With Sheets("Sheet2")
.Range("A" & .Cells(.Rows.Count, 1).End(xlUp).Offset(1).Row).PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
.Paste
End With
Application.CutCopyMode = False
Set loc = rSearchRng.FindNext(loc)
Loop While loc.Address <> locFirstAddress
End If
Set loc = Nothing
MsgBox "Complete"
End Sub

Related

macro to copy multiple cell ranges and paste in a row on another sheet

I recorded a macro, What I'm trying to obtain is creating a code that will copy the following range in the code on each worksheet and paste it in rows underneath each other on sheet "Master".
I have the following code:
Sub Macro1()
'
' Macro1 Macro
'
'
Dim rng As Range
Sheets("AL-Jackson Hospital-Fvar").Select
Set rng = Range( _
"K50:M50,K58:M58,K59:M59,K55:M55,K12:M12,K14:M14,K24:L24,K28:L28,K29:L29,K35:L35,K62:L62,K32:L32,K30:L30,K31:L31,K63:L63,K33:L33,K34:L34,K37:L37,K40:L40,K41:L41,K42:L42,K46:L46" _
)
rng.Select
Selection.Copy
Sheets("Master").Select
Range("B4").Select
Range("B4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ActiveWindow.ScrollWorkbookTabs Position:=xlFirst
End Sub
For example:
On sheet 1, 2 ,3 Copy the following range on each sheet and paste as values in sheet Master starting in Cell B1. So sheet 1 data range should be in B1, sheet 2 data range should be in b2, and sheet 3 data range should be in b3 and etc....
Guys my workbook has over 50 sheets
Something like should work for you:
Sub tgr()
Dim wb As Workbook
Dim ws As Worksheet
Dim wsDest As Worksheet
Dim rCell As Range
Dim aData() As Variant
Dim sCells As String
Dim i As Long, j As Long
Set wb = ActiveWorkbook
Set wsDest = wb.Sheets("Master")
sCells = "K50:M50,K58:M58,K59:M59,K55:M55,K12:M12,K14:M14,K24:L24,K28:L28,K29:L29,K35:L35,K62:L62,K32:L32,K30:L30,K31:L31,K63:L63,K33:L33,K34:L34,K37:L37,K40:L40,K41:L41,K42:L42,K46:L46"
ReDim aData(1 To wb.Sheets.Count - 1, 1 To wsDest.Range(sCells).Cells.Count)
i = 0
For Each ws In wb.Sheets
If ws.Name <> wsDest.Name Then
i = i + 1
j = 0
For Each rCell In ws.Range(sCells).Cells
j = j + 1
aData(i, j) = rCell.Value
Next rCell
End If
Next ws
wsDest.Range("B1").Resize(UBound(aData, 1), UBound(aData, 2)).Value = aData
End Sub
here's an alternative "formula" approach
other than putting in an alternative approach, it also reduces the number of iterations from (nsheets-1)*ncells (as per tigeravatar's solution) to (nsheets-1) + ncells, should it ever be a relevant issue
Option Explicit
Sub main()
Dim ws As Worksheet
Dim cell As Range, refCell As Range
With ActiveWorkbook.Sheets("Master")
For Each ws In wb.Sheets
.Cells(.Rows.Count, 1).End(xlUp).Offset(1) = IIf(ws.Name <> .Name, ws.Name, "")
Next ws
Set refCell = .Cells(.Rows.Count, 1).End(xlUp).Offset(1)
For Each cell In Range("K50:M50,K58:M58,K59:M59,K55:M55,K12:M12,K14:M14,K24:L24,K28:L28,K29:L29,K35:L35,K62:L62,K32:L32,K30:L30,K31:L31,K63:L63,K33:L33,K34:L34,K37:L37,K40:L40,K41:L41,K42:L42,K46:L46")
.Cells(refCell.Row, .Columns.Count).End(xlToLeft).Offset(, 1).Value = cell.Address ' set the reference for INDIRECT() function
Next cell
With .Range("B2", .Cells(refCell.Row, .Columns.Count).End(xlToLeft).Offset(-1))
.FormulaR1C1 = "=INDIRECT(ADDRESS(ROW(INDIRECT(R" & refCell.Row & "C)),COLUMN(INDIRECT(R" & refCell.Row & "C)),,,RC1))"
.Value = .Value
.Offset(.Rows.Count).Resize(1).ClearContents
End With
End With
End Sub
it leaves the sheets name in column "A": they can be removed

Dynamically Name Sheet from Cell and Later Call Name of Worksheet

In the code below, I am building a table on the "Shipped" sheet by pulling data from the "Efficiency" sheet using the criteria "Ship". I want to name the "Shipped" sheet dynamically from a cell by using something like Application.ActiveSheet.Name = .Range("A2") and then use that to call the sheet using something like Set wsShip = Worksheets.Range("A2") and I also want to use a dynamic criteria for pulling data, so instead of using Criteria1:="Ship"I want to use Criteria1:=.Range("A3") Is there any/another way to do this?
Sub DataTable()
Dim wsEff As Worksheet
Dim wsShip As Worksheet
''Application.ActiveSheet.Name = Range("A2")
'Need ' Set wsShip = Worksheets(Range("A2"))?
Set wsShip = Worksheets("Shipped")
Set wsEff = Worksheets("Efficiency")
With wsEff
Dim lRow As Long
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A1:H" & lRow).AutoFilter Field:=2, Criteria1:="Ship"
Dim rngCopy As Range
'All Columns A:H
Set rngCopy = .Columns("A:H")
'filtered rows, not including header row - assumes row 1 is headers
Set rngCopy = Intersect(rngCopy, .Range("A1:H" & lRow), .Range("A1:H" & lRow).Offset(1)).SpecialCells(xlCellTypeVisible)
rngCopy.Copy
End With
wsShip.Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Worksheets("Efficiency").ShowAllData
End Sub
Set wsShip = Worksheets("Shipped")
Set wsEff = Worksheets("Efficiency")
wsShip.Name = wsEff.Range("A2").Value 'for example
wsShip.Activate 'changing the name doesn't change the reference to
' the sheet you have in 'wsShip'

Show Whole Table After Null Search

for the code below, if a search comes up empty based on Criteria1:="Ship", then there is nothing to copy, and the code stops at Set rngCopy = Intersect(rngCopy, .Range("A1:H" & lRow), .Range("A1:H" & lRow).Offset(1)).SpecialCells(xlCellTypeVisible), how can I get rid of this bug? Additionally, I want the whole table to show even if no data meets the criteria. I have the line Worksheets("Efficiency").ShowAllData but this is under the assumption the code runs all the way.
Thanks,
Sub ImportShipper()
Dim wsEff As Worksheet
Dim wsShip As Worksheet
Dim wsFirst As Worksheet
Set wsEff = Worksheets("Efficiency")
Set wsFirst = Worksheets("1")
Set wsShip = ActiveSheet
wsShip.Name = wsFirst.Range("B34").Value
With wsEff
Dim lRow As Long
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A1:H" & lRow).AutoFilter Field:=2, Criteria1:="Ship"
Dim rngCopy As Range
'All Columns A:H
Set rngCopy = .Columns("A:H")
'filtered rows, not including header row - assumes row 1 is headers
Set rngCopy = Intersect(rngCopy, .Range("A1:H" & lRow), .Range("A1:H" & lRow).Offset(1)).SpecialCells(xlCellTypeVisible)
rngCopy.Copy
End With
wsShip.Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Worksheets("Efficiency").ShowAllData
End Sub
you could go like this
Option Explicit
Sub ImportShipper()
Dim wsEff As Worksheet
Dim wsShip As Worksheet
Dim wsFirst As Worksheet
Set wsEff = Worksheets("Efficiency")
Set wsFirst = Worksheets("1")
Set wsShip = ActiveSheet
wsShip.Name = wsFirst.Range("B34").value
With wsEff
Dim lRow As Long
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("A1:H" & lRow)
.AutoFilter Field:=2, Criteria1:="Ship"
With .Offset(1).Resize(.Rows.Count - 1)
If Application.WorksheetFunction.Subtotal(103, .Columns(2)) > 0 Then
.SpecialCells(xlCellTypeVisible).Copy
wsShip.Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
End With
End With
End With
Worksheets("Efficiency").ShowAllData
End Sub

Trouble with Copy/Paste Cells with a Certain String Name in Them, VBA

I am using this code to check each row in worksheet "Report2" for the phrase "Chicago" and copy and paste any rows with "Chicago" in them into a new sheet. However, it is not working. Any help on why would be appreciated.
Sub BranchCount()
Dim s As Worksheet
Dim LastRow As Long
Set s = Worksheets("Report 1")
LastRow = s.UsedRange.SpecialCells(xlCellTypeLastCell).Row
Worksheets("Report 1").Select
Range("A1:J" & LastRow).Select
Selection.Copy
Sheets.Add.Name = "Report2"
Selection.PasteSpecial xlPasteValues
Range("A1").EntireRow.Delete
Range("B1").EntireRow.Delete
Range("C1").EntireRow.Delete
Dim Z As Range
Dim Y As String
Y = "Chicago"
Dim Q As Worksheet
Dim LastRow2 As Long
Set Q = Worksheets("Report2")
LastRow2 = Q.UsedRange.SpecialCells(xlCellTypeLastCell).Row
Sheets("Report2").Range("A1").Select
For Each Z In Range("J1:J" & LastRow2)
If Y = Z.Value Then
Z.EntireRow.Copy
Sheets("Clean").Select
Range("A500").End(xlUp).Offset(1, 0).Select
Selection.PasteSpecial xlPasteValues
Sheets("Report2").Select
End If
Next
End Sub
I use Excel 2013. Please let me know if you can help. Thanks!
I tried some cleaning up, using worksheet variables. You started using them, but should implement them everywhere (again, see the link in my comment).
I think I understood where your data was, but you may need to tweak the below (use F8 to step through one line at a time):
Sub BranchCount()
Dim rptOneWS As Worksheet, rptTwoWS As Worksheet
Dim s As Worksheet
Dim LastRow As Long
Set rptOneWS = Worksheets("Report 1")
Set rptTwoWS = Sheets.Add
rptTwoWS.Name = "Report 2"
LastRow = rptOneWS.UsedRange.SpecialCells(xlCellTypeLastCell).Row
'If you just want values, set two ranges equal. That way you
' skip using the clipboard
rptTwoWS.Range("A1:J" & LastRow).Value = rptOneWS.Range("A1:J" & LastRow).Value
With rptTwoWS
.Range(.Rows(1), .Rows(3)).EntireRow.Delete
End With
Dim Z As Range
Dim Y As String
Y = "Chicago"
Dim LastRow2 As Long
LastRow2 = rptTwoWS.UsedRange.SpecialCells(xlCellTypeLastCell).Row
For Each Z In rptTwoWS.Range("J1:J" & LastRow2)
If Y = Z.Value Then
Z.EntireRow.Copy
Sheets("Clean").Range("A500").End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
End If
Next
End Sub

Macro populates wrong values - current date

I would like to ask for a help. My Macro was about to populate the current date to all populated rows. At the begining it seemed to work and suddenly it started to change (overwrite) the header to the current date and put the current date in 1 cell below. Could anyone help me what should I amend to make it work properly?
Here is the macro code (reformatted):
Sub DateVerified()
Sheets("Data").Activate
Dim rngAddress As Range
Set rngAddress = Range("A1:ZZ1").Find("Verified Date").Offset(1, 0)
rngAddress.Select
Dim ac As Integer
Dim lastr As Long
Dim sh As Worksheet
Set sh = ActiveSheet
ac = ActiveCell.Column
lastr = sh.Cells(Rows.Count, ac).End(xlUp).Row
Range(Cells(2, ac), Cells(lastr, ac)).Select
Selection.ClearContents
Selection.Formula = "=TEXT(Now(),""dd/mm/yyyy"")"
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
The following might suit:
Sub DateVerified()
Dim rngAddress As Range
Dim ac As Integer
Dim lastr As Long
Dim sh As Worksheet
Sheets("Data").Activate
Set rngAddress = Range("A1:ZZ1").Find("Verified Date").Offset(1, 0)
rngAddress.Select
Set sh = ActiveSheet
lastr = sh.Cells(Rows.Count, 1).End(xlUp).Row
ac = ActiveCell.Column
Range(Cells(2, ac), Cells(lastr, ac)).Select
Selection.ClearContents
Selection.Formula = "=TEXT(Now(),""dd/mm/yyyy"")"
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues
End Sub
I think that this is likely to be going wrong on the line below:
lastr = sh.Cells(Rows.Count, ac).End(xlUp).Row
This attempts to go to the final row of the spreadsheet for the active column and then do the equivalent of ctrl+up in excel to find the last row populated in that column. To test this theory add a line of code directly after this:
debug.print "lastr set to " & lastr
and see what this value is set to looking at the immediate window (use Ctrl+G to open from the VBA editor).