VBA loop merging cells in specific range - vba

I have a specified range and want to merge the cells A-D per row. I'm not sure which loop would be the best, and have messed around with different ones and the problem I have run into, is either an object-defined error or merging the entire range into one cell.
Sub Merge()
Dim EndRangeRE As Range
Dim EndRangeNRE As Range
Dim rngall As Range
Dim StartRangeNRE As Range
Dim StartRangeRE As Range
Dim looprng As Range
Sheets("{Activity} 7300-1input template").Activate
Set rngall = Sheets("{Activity} 7300-1input template").UsedRange
Set EndRangeRE = rngall.Find(What:="10. Other Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set EndRangeNRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues,LookAt:=xlWhole, MatchCase:=True)
Set StartRangeNRE = rngall.Find(What:="Non-Recurring Costs",LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues,LookAt:=xlWhole, MatchCase:=True)
Set looprng = Sheets("{Activity} 7300-1input template").Range(StartRangeNRE, EndRangeRE)
For Each Row In looprng
Cells(0, 4).Merge
Next Row
End Sub
This one gives me an error and I'm not sure how to specify to do each row, A:D merge and next row. Would it be a do loop? I'm very open to the easiest way to make this happen so suggestions are gladly welcomed (I'm not too experienced in coding so anything to help me learn!). Thanks!

maybe you're after this:
Option Explicit
Sub Merge()
Dim EndRangeRE As Range, StartRangeNRE As Range
Dim myRow As Range
With Sheets("{Activity} 7300-1input template")
With .UsedRange
Set EndRangeRE = .Find(What:="10. Other Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeNRE = .Find(What:="Non-Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
End With
For Each myRow In .Range(StartRangeNRE, EndRangeRE).Rows
.Rows(myRow.row).Resize(, 4).Merge
Next
End With
End Sub
where I got rid of unused variables and use some With-End With block to reference multiple reference of the same object

This will merge A through D for 100 rows:
Sub ytrewq()
For i = 1 To 100
Range("A" & i & ":D" & i).MergeCells = True
Next i
End Sub
EDIT#1:
Sub ytrewq()
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
Range("A" & i & ":D" & i).MergeCells = True
Next i
End Sub

Try This code :
Sub test()
'Get The Last non empty row
lastRow = ThisWorkbook.Sheets("YourSheetName").Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lastRow
ThisWorkbook.Sheets("YourSheetName").Range("A" & i & ":D" & i).Merge
Next i
End Sub

The code below incoropates Merging cells in columns "A:D" in your looprng range.
Code
Option Explicit
Sub Merge()
Dim EndRangeRE As Range
Dim EndRangeNRE As Range
Dim rngall As Range
Dim StartRangeNRE As Range
Dim StartRangeRE As Range
Dim looprng As Range
' 2 added object variables
Dim Sht As Worksheet
Dim myRow As Range
' set your worksheet object, don't need to Activate it
Set Sht = ThisWorkbook.Sheets("{Activity} 7300-1input template")
Set rngall = Sht.UsedRange
Set EndRangeRE = rngall.Find(What:="10. Other Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set EndRangeNRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeNRE = rngall.Find(What:="Non-Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set StartRangeRE = rngall.Find(What:="Recurring Costs", LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
Set looprng = Sht.Range(StartRangeNRE, EndRangeRE)
' merge cells in columns "A:D" in your range
For Each myRow In looprng.Rows
Sht.Range(Sht.Range("A" & myRow.Row), Sht.Range("D" & myRow.Row)).Merge
Next myRow
End Sub

Related

Inserting Range into Array in VBA for iteration

I am facing some issues with VBA. Let me explain what I am trying to achieve. I have 2 sheets in 1 workbook. They are labelled "Sheet1" and "Sheet2."
In "Sheet1," there are 100 rows and 100 columns. In column A, it is filled with eg: SUBJ001 all the way to SUBJ100. In "Sheet2," there is only 1 Column A, with a range of rows. Eg: "SUBJ003, SUBJ033, SUBJ45." What I am trying to achieve is to use my mouse, highlight the column A in "Sheet2," and compare each individual cell with the cells in column A. Should there be a match, it will copy the entire row and paste them in a new sheet that the macro creates in the same workbook. However, i am experiencing an out of range error at Set Rng =.Find(What:=Arr(I), ... Thanks!
Sub Copy_To_Another_Sheet_1()
Dim FirstAddress As String
Dim MyArr As Variant
Dim Rng As Range
Dim Rcount As Long
Dim I As Long
Dim NewSh As Worksheet
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set Rng = Application.InputBox("Select target range with the mouse", Type:=8)
MyArr = Rng
Set NewSh = Worksheets.Add
With Sheets("Sheet1").Range("A:A")
Rcount = 0
For I = LBound(MyArr) To UBound(MyArr)
Set Rng = .Find(What:=MyArr(I), _
After:=.Cells(.Cells.Count), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
Rcount = Rcount + 1
Rng.EntireRow.Copy NewSh.Range("A" & Rcount)
' Use this if you only want to copy the value
' NewSh.Range("A" & Rcount).Value = Rng.Value
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
Next I
End With
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
MyArr = Rng is setting MyArr to be a two-dimensional array where the first rank corresponds to the rows in Rng and the second rank corresponds to the columns in Rng.
Assuming you only have one column in Rng, then your Find statement should refer to the values in that first column using MyArr(I, 1), i.e.
Set Rng = .Find(What:=MyArr(I, 1), _
After:=.Cells(.Cells.Count), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)

Excel VBA: What am I missing in this simple OFFSET?

Code finds the header row and correct column. I want to execute some code on the range starting one cell under the header row in the same column and down to the last row in the same column. I've tried to use offset to create the range but the offset fails every time. Can offset not be used this way?
Sub Del_Y_Rows()
Dim Rng, fcell, LastRow, SrchRng, sRNG, eRNG As Range
Dim Findstring As String
Findstring = "Header"
With Sheets("thisSheet")
Set SrchRng = .Range("a1:l15")
Set fcell = SrchRng.Find(What:=Findstring, _
LookAt:=xlWhole, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
MatchCase:=False)
LastRow = .Cells(Rows.Count, fcell.Column - 2).End(xlUp).Row
Debug.Print "fcell " & fcell.Address
sRNG = .Range(fcell).Offset(1, 0) 'this fails 'sRng = start of the range
Debug.Print "srng " & sRNG
eRng = .cells(LastRow, fcell.Column) 'eRng = end of the range
Rng = .Range(sRNG, eRng)
Debug.Print "rng is " & Rng.Address
End With
End Sub
fcell is a range and the RAnge() is not needed:
sRNG = fcell.Offset(1, 0)
One more thing, You will want to use a check to make sure the fcell is actually a range and not nothing.
Sub Del_Y_Rows()
Dim Rng As Range, fcell As Range, LastRow as Long , SrchRng As Range, sRNG As Range, eRNG As Range
Dim Findstring As String
Findstring = "Header"
With Sheets("thisSheet")
Set SrchRng = .Range("a1:l15")
Set fcell = SrchRng.Find(What:=Findstring, _
LookAt:=xlWhole, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
MatchCase:=False)
LastRow = .Cells(Rows.Count, fcell.Column - 2).End(xlUp).Row
If not fcell is nothing then
Debug.Print "fcell " & fcell.Address
set sRNG = fcell.Offset(1, 0) 'this fails 'sRng = start of the range
Debug.Print "srng " & sRNG
set eRng = .cells(LastRow, fcell.Column) 'eRng = end of the range
set Rng = .Range(sRNG, eRng)
Debug.Print "rng is " & Rng.Address
End If
End With
End Sub
You must use Set for objects.
Set sRNG = .Range(fcell).Offset(1, 0)

Add location of cell to SUM formula

Is there any way to add the location of a cell into a SUM formula?
I have the following For Each ... Next loop, but instead of merely counting the number of cells that contain a value of 1, I would like to add the specific location of such a cell into a SUM formula.
Dim rng As Range, cell As Range
Set rng = Range("I3:DC70")
For Each cell In rng
If cell.Value = 1 Then Range("DF4").Value = Range("DF4").Value + 1
Next cell
Is this possible?
You will have to use .Find and .FindNext. You can read about it Here. This approach is much faster than looping when you have a large dataset.
Here is something that I wrote quickly. Please amend it to suit your needs.
Sub Find_Cells_Which_Has_My_Damn_String()
Dim WhatToFind As String
Dim aCell As Range, bCell As Range
Dim SearchRange As Range, rng As Range
Dim ws As Worksheet
'~~> Set this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
'~~> Set here what to find
WhatToFind = "1"
'~~> Set this to the relevant range
Set SearchRange = ws.Cells
Set aCell = SearchRange.Find(What:=WhatToFind, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
Set rng = aCell
Do
Set aCell = SearchRange.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
Set rng = Union(rng, aCell)
Else
Exit Do
End If
Loop
End If
If Not rng Is Nothing Then MsgBox rng.Address Else _
MsgBox "No cells were found containing " & WhatToFind
End Sub
Screenshot

.Find function and Offset cells working for constants but not formulas

The following code is similar to a Vlookup function. Was wondering why the same For Each...Next loop works when applied to Constants but not when it's applied to Formulas.
Thank you
Dim ws1 As Worksheet, ws2 As Worksheet
Dim SourceRange As Range, TargetRange As Range, TargetCell As Range,
Dim SourceCell As Range, SourceColumn As Range, TargetColumn As Range,
Dim TargetRangeConstant As Range, TargetRangeFormula As Range
On Error Resume Next
'set Worksheets and Ranges
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet1")
Set SourceRange = ws1.Range("A:A")
Set TargetRange = ws2.Range("L:L")
Set SourceColumn = ws1.Range("C:C")
Set TargetColumn = ws2.Range("O:O")
Set TargetRangeConstant = TargetRange.SpecialCells(xlConstants)
Set TargetRangeFormula = TargetRange.SpecialCells(xlFormulas)
'For Constants
For Each TargetCell In TargetRangeConstant
Set SourceCell = SourceRange.Find(What:=TargetCell, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not TargetCell Is Nothing Then
'"copies" cells in source to target
TargetCell.Offset(, TargetColumn.Column - TargetRange.Column) = SourceCell.Offset(, SourceColumn.Column - SourceRange.Column)
End If
Next
'Same Function but for Formulas
For Each TargetCell In TargetRangeFormula
Set SourceCell = SourceRange.Find(What:=TargetCell, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not TargetCell Is Nothing Then
'"copies" cells in source to target
**TargetCell.Offset(, TargetColumn.Column - TargetRange.Column) = SourceCell.Offset(, SourceColumn.Column - SourceRange.Column)**
End If
Next
You should be using TargetCell.Formula in the second block. In my sample code below, A1 in Sheet1 has =SUM(B1:C1). In Sheet2, it is in D1. It returns the correct address.
Sub Test()
Dim TargetCell As Range
Dim TargetF, TestS As String
Set TargetCell = Sheet1.Range("A1")
TargetF = TargetCell.Formula
TestS = Sheet2.Cells.Find(What:=TargetF, LookIn:=xlFormulas).Address
MsgBox TestS 'Returns D1.
End Sub
Let us know if this works.

Creating an Excel Macro to Delete multiple rows at once

I found a code online and want to make edits to it. The code is in VBA and I want the macro code to delete multiple rows rather than one. Here is the code:
Sub findDelete()
Dim c As String
Dim Rng As Range
c = InputBox("FIND WHAT?")
Set Rng = Nothing
Set Rng = Range("A:A").Find(what:=c, _
After:=Range("A1"), _
LookIn:=xlFormulas, _
lookat:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
Rng.EntireRow.Delete shift:=xlUp
End Sub
Instead of using find, use Autofilter and delete the VisibleCells
Sub findDelete()
Dim c As String, Rng As Range, wks as Worksheet
c = InputBox("FIND WHAT?")
Set wks = Sheets(1) '-> change to suit your needs
Set Rng = wks.Range("A:A").Find(c, After:=Range("A1"), LookIn:=xlFormulas, _
lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
With wks
.Range(.Range("A1"), .Range("A" & .Rows.Count).End(xlUp)).AutoFilter 1, c
Set Rng = Intersect(.UsedRange, .UsedRange.Offset(1), .Range("A:A")).SpecialCells(xlCellTypeVisible)
Rng.Offset(1).EntireRow.Delete
End With
End If
End Sub
EDIT
To replace the InputBox with Multiple Values to Find / Delete Do This:
Option Explicit
Sub FindAndDeleteValues()
Dim strValues() as String
strValues() = Split("these,are,my,values",",")
Dim i as Integer
For i = LBound(strValues()) to UBound(strValues())
Dim c As String, Rng As Range, wks as Worksheet
c = strValues(i)
'.... then continue with code as above ...
Next
End Sub
Just wrap it up in a While loop.
Sub findDelete()
Dim c As String
Dim Rng As Range
c = InputBox("FIND WHAT?")
Set Rng = Nothing
Do While Not Range("A:A").Find(what:=c) Is Nothing
Set Rng = Range("A:A").Find(what:=c, _
After:=Range("A1"), _
LookIn:=xlFormulas, _
lookat:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
Rng.EntireRow.Delete shift:=xlUp
Loop
End Sub
You already have the code to delete rows in Rng.EntireRow.Delete shift:=xlUp, what you need is the code to set the range to the rows which you want to delete. As usual in VBA, this can be done in a lot of ways:
'***** By using the Rng object
Set Rng = Rows("3:5")
Rng.EntireRow.Delete shift:=xlUp
Set Rng = Nothing
'***** Directly
Rows("3:5").EntireRow.Delete shift:=xlUp
Your Find statement only finds the first occurrence of c, that's why it's not deleting more that one row.