Increment months in next available column, but multiple rows - excel

I have VBA code which increments dates in the active cell to the next available column.
Dim lngLastCol As Long, lngRow As Long
lngRow = ActiveCell.Row
lngLastCol = Cells(lngRow, Columns.Count).End(xlToLeft).Column
If IsDate(Cells(lngRow, lngLastCol)) Then
With Cells(lngRow, lngLastCol + 1)
.Value = DateAdd("M", 1, CDate(Cells(lngRow, lngLastCol)))
.NumberFormat = Cells(lngRow, lngLastCol).NumberFormat
End With
End If
Instead of incrementing the month (and year) on the active row I am currently clicked on, I want to update the months in certain fixed rows i.e. Row 3, 17 and 42 (all in the same column).

Another approach, loop one column to the last row (in this case 250). In the second If formula you set which rows to add new columns to. So if this statement is true Cells(i, 2).Row = 3 (current row we loop is 3) then add a new column.
Therefore we replace the active row with a loop:
lngRow = ActiveCell.Row -> lngRow = Cells(i, 2).Row
The For i loop will from row 3 to row 250.
Sub ColumnsAdd()
Dim lngLastCol As Long, lngRow As Long, i As Long
For i = 3 To 250 'Loop from row 3 to 250
If Cells(i, 2).Row = 3 Or Cells(i, 2).Row = 17 Or Cells(i, 2).Row = 42 Then 'If any of the rows is 3, 17 or 42 then go and add new column
lngRow = Cells(i, 2).Row
lngLastCol = Cells(lngRow, Columns.Count).End(xlToLeft).Column
If IsDate(Cells(lngRow, lngLastCol)) Then
With Cells(lngRow, lngLastCol + 1)
.Value = DateAdd("M", 1, CDate(Cells(lngRow, lngLastCol)))
.NumberFormat = Cells(lngRow, lngLastCol).NumberFormat
End With
End If
End If
Next i
End Sub

I dont understand exactly what to you want but you can use the below code and if you want more adjustment let me know.
Option Explicit
Sub test()
Dim lngLastCol As Long, lngRow As Long
lngRow = ActiveCell.Row
lngLastCol = Cells(lngRow, Columns.Count).End(xlToLeft).Column
If IsDate(Cells(lngRow, lngLastCol)) Then
With Union(Cells(3, lngLastCol + 1), Cells(17, lngLastCol + 1), Cells(42, lngLastCol + 1))
.Value = DateAdd("M", 1, CDate(Cells(lngRow, lngLastCol)))
.NumberFormat = Cells(lngRow, lngLastCol).NumberFormat
End With
End If
End Sub

Related

VBA Delete lines based on cells values

I have a monthly report with 25K-30K lines from which I want to delete lines based on cell values. The report has a dynamic number of rows each month but the number of columns are fixed, from A to X. I am using the For Next Loop to search into the cells for the values that will trigger the deletion of rows, in the worksheet "Data" of the report. There is a second sheet in this report named "Public accounts" where the macro searches and adds a tag (public or private) into each of the rows in the "Data" sheet. It then checks several conditions (like if the values of the cells in columns R and S are equal then the line is deleted) using the For Next loop and if they are true the lines are deleted in the "Data" sheet of the report.
My problem is that it takes far too long to run (10-15 mins) in its condition. Can you please help me to speed it up? I am attaching the code that I am using.
Sub Format_Report()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Worksheets("Data").Activate
LR = Range("A" & Rows.Count).End(xlUp).Row
Range("X2").Formula = "=if(isnumber(Match(A2,'Public accounts'!A:A,0)),""Public"",""Private"")"
Range("X2").AutoFill Destination:=Range("X2:X" & LR)
Last = Cells(Rows.Count, "A").End(xlUp).Row
For i = Last To 1 Step -1
If (Cells(i, "R").Value) = (Cells(i, "S").Value) Then
Cells(i, "A").EntireRow.Delete
End If
Next i
For i = Last To 1 Step -1
If (Cells(i, "G").Value) = "ZRT" Then
Cells(i, "A").EntireRow.Delete
End If
Next i
For i = Last To 1 Step -1
If (Cells(i, "G").Value) = "ZAF" Then
Cells(i, "A").EntireRow.Delete
End If
Next i
For i = Last To 1 Step -1
If (Cells(i, "G").Value) = "E" Then
Cells(i, "A").EntireRow.Delete
End If
Next i
For i = Last To 1 Step -1
If Cells(i, 24) = "Public" Then
Cells(i, 24).EntireRow.Delete
End If
Next i
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Please, test the next code. It should work very fast, using arrays, sort, delete at once, resort and clear the helper sort column:
Sub Format_Report()
Dim wsD As Worksheet, lastRD As Long, lastCol As Long
Dim arr, arrMark, arrSort, i As Long, boolFound As Boolean
Set wsD = ActiveSheet 'Worksheets("Data")
lastRD = wsD.Range("A" & wsD.rows.count).End(xlUp).row
lastCol = wsD.UsedRange.column + wsD.UsedRange.Columns.count + 1
arrSort = Evaluate("row(1:" & lastRD & ")") 'build an array to resort after deletion
wsD.Range("X2:X" & lastRD).Formula = "=if(isnumber(Match(A2,'Public accounts'!A:A,0)),""Public"",""Private"")"
wsD.Calculate
arr = wsD.Range("G1:X" & lastRD).Value2 'place the range in an array for faster iteration
ReDim arrMark(1 To UBound(arr), 1 To 1) 'reDim the array to keep deletion marks
For i = 1 To lastRD
If arr(i, 12) = arr(i, 13) And (arr(i, 12) <> "") Or _
arr(i, 1) = "ZRT" Or _
arr(i, 1) = "ZAF" Or _
arr(i, 1) = "E" Or _
arr(i, 18) = "Public" Then
arrMark(i, 1) = "Del": boolFound = True 'write in array an boolFound = true to confirm at least a row to be deleted
End If
Next i
Application.ScreenUpdating = False: Application.DisplayAlerts = False
wsD.cells(1, lastCol).Resize(UBound(arrMark), 1).Value2 = arrMark 'drop arrMark content at once:
wsD.cells(1, lastCol + 1).Resize(UBound(arrSort), 1).Value2 = arrSort
'sort the range based on arr column:
wsD.Range("A1", wsD.cells(lastRD, lastCol + 1)).Sort key1:=wsD.cells(1, lastCol), Order1:=xlAscending, Header:=xlNo ' sort the range by deletion column
With wsD.cells(1, lastCol).Resize(lastRD, 1)
If boolFound Then 'if at least a row to be deleted:
.SpecialCells(xlCellTypeConstants).EntireRow.Delete
End If
End With
'Resort the range based on arrSort column:
wsD.Range("A1", wsD.cells(lastRD, lastCol + 1)).Sort key1:=wsD.cells(1, lastCol), Order1:=xlAscending, Header:=xlNo
wsD.cells(lastRD, lastCol + 1).EntireColumn.ClearContents 'clear the column with the initial order
Application.ScreenUpdating = True: Application.DisplayAlerts = True
MsgBox "Ready..."
End Sub

vba for loop for 4 different column

Dim I As Long
For I = 2 To lastrow
If Not IsEmpty(Cells(I, "f")) And IsEmpty(Cells(I, "j")) Then
Cells(I, "j").Value = "unregister"
End If
Next I
Dim I2 As Long
For I2 = 2 To lastrow
If IsEmpty(Cells(I2, "f")) Then
Cells(I2, "i").Value = Cells(I2 - 1, "i").Value
End If
Next I2
can you make this code more simple i want to copy above row for 3 different column if column f is empty
You can do something like this, using a single loop and Offset(-1, 0) to get the cell above:
Dim i As Long, ws As Worksheet
Set ws = ActiveSheet
For i = 2 To ws.Cells(ws.Rows.Count, "F").End(xlUp).Row
With ws.Rows(i)
If Not IsEmpty(.Columns("F")) Then
If IsEmpty(.Columns("J")) Then .Columns("J").Value = "unregister"
Else
.Columns("I").Value = .Columns("I").Offset(-1, 0).Value
.Columns("L").Value = .Columns("L").Offset(-1, 0).Value
'etc
End If
End With
Next I2

Copying a value down into inserted blank rows over multiple columns

I have a sheet with multiple columns and in column A there is data where I have removed the duplicates.
This is the code to insert nine blank lines below each of the unique values.
Sub RowAdder()
Dim i As Long, col As Long, lastRow As Long
col = 1 lastRow = Cells(Rows.Count, col).End(xlUp).Row
For i = lastRow To 3 Step -1
If Cells(i - 1, col) <> Cells(i, col) Then
Range(Cells(i, col).EntireRow, Cells(i + 8, col).EntireRow).Insert shift:=xlDown
End If
Next I
End Sub
I need to adapt this code to copy the values of each unique value to the blank lines below for column A to C.
On the last line I need the value to be copied down into 9 blank rows.
maybe you'ar after something like this
Sub RowAdder()
Dim i As Long, col As Long
col = 1
With Range(Cells(2, col), Cells(Rows.Count, col).End(xlUp))
For i = .Rows(.Rows.Count).Row To 3 Step -1
If Cells(i - 1, col) <> Cells(i, col) Then Range(Cells(i, col).EntireRow, Cells(i + 8, col).EntireRow).Insert shift:=xlDown
Next i
With .Resize(.Rows.Count + 9)
With .SpecialCells(xlCellTypeBlanks)
.FormulaR1C1 = "=R[-1]C"
Intersect(.EntireRow, Range("B:C")).FormulaR1C1 = "=RC[-1]"
End With
With Intersect(.EntireRow, Range("A:C"))
.Value = .Value
End With
End With
End With
End Sub

Copy ranges and multiply in loop

Ive been searching left and right but seem to only find bits and pieces. i'm unable to combine these into the solution i need.
My workbook has a list of items on the first sheet, the partnumbers in column A have to be searched for in Column A of a second sheet and if they exist there, those rows need to be copied to a third sheet.In steps i'm looking to do the following:
Column A of sheet1 (called "input") has several partnumbers.
After clicking CommandButton2 on sheet1, all partnumbers in Column A (starting in cell A5)should be searched for in Column A of sheet3 (called "partlists", starting in A2).
If found here, for all the respective rows where the partnumbers match: columns C to G("partlists") should be copied to sheet2("picklist") column A below the last row, the value in column E("picklist") has to be multiplied with the value in Column E("input") AND columns G to K("input") copied to the respective rows column G("Picklist")
If not found on "partlists", copy entire row from "input" to "picklist" below last row.
So far i've got the following code:
Sub InputPickMatch()
Dim LR As Long, i As Long, lngNextRow As Long, LookUpListInput As Range, LookUpListParts As Range
Set LookUpListInput = Sheets("Input").Range("A:A") 'lookup list Input
Set LookUpListParts = Sheets("Partlists").Range("A:A")
With Sheets("Input")
LR = .Cells(Rows.Count, "A").End(xlUp).Row 'last row
For i = 5 To LR
If IsError(Application.Match(.Cells(i, "A").Value, LookUpListParts, 0)) Then
.Range(Cells(i, "A").Address(), Cells(i, "D").Address()).Copy
Sheets("Picklist").Select
lngNextRow = Sheets("Picklist").Range("A" & Rows.Count).End(xlUp).Row + 1
Sheets("Picklist").Range("A" & lngNextRow).PasteSpecial _
Paste:=xlPasteValues
.Range(Cells(i, "F").Address(), Cells(i, "K").Address()).Copy
Sheets("Picklist").Range("E" & lngNextRow).PasteSpecial _
Paste:=xlPasteValues
End If
Next i
End With
With Sheets("Partlists")
LR = .Cells(Rows.Count, "A").End(xlUp).Row 'last row
For i = 3 To LR
If IsNumeric(Application.Match(.Cells(i, "A").Value, LookUpListInput, 0)) Then
.Range(Cells(i, "C").Address(), Cells(i, "G").Address()).Copy
Sheets("Picklist").Select
lngNextRow = Sheets("Picklist").Range("A" & Rows.Count).End(xlUp).Row + 1
Sheets("Picklist").Range("A" & lngNextRow).PasteSpecial _
Paste:=xlPasteValues
'Sheets("Picklist").Cells(lngNextRow, "E") = Sheets("Input").Cells(LookUpListInput, "E") * .Cells(i, "G") 'NOT WORKING: Multiply row from lookuplist column E with .Cells(i, "G")
'Sheets("Input").Range(Cells(LookUpList, "G").Address(), Cells(LookUpListInput, "K").Address()).Copy 'NOT WORKING: Copy row from lookuplist column G:K
'Sheets("Picklist").Range("F" & lngNextRow).PasteSpecial 'Paste Picklist column G
End If
Next i
End With
End Sub
It's working ok up to where i try to multiply and copy from the lookup list.
Hopefully someone can help
I got it guys
Sub InputToPicklist()
Dim LR As Long, i As Long, lngNextRow As Long, LookUpListInput As Range, LookUpListParts As Range
Dim Matchres As Variant
Set LookUpListInput = Sheets("Input").Range("A:A")
Set LookUpListParts = Sheets("Partlists").Range("A:A")
With Sheets("Input")
LR = .Cells(Rows.Count, "A").End(xlUp).Row
For i = 5 To LR
If IsError(Application.Match(.Cells(i, "A").Value, LookUpListParts, 0)) Then
lngNextRow = Sheets("Picklist").Range("A" & Rows.Count).End(xlUp).Row + 1
Sheets("Picklist").Range(Cells(lngNextRow, "A").Address(), Cells(lngNextRow, "D").Address()).Value = .Range(Cells(i, "A").Address(), Cells(i, "D").Address()).Value
Sheets("Picklist").Range(Cells(lngNextRow, "E").Address(), Cells(lngNextRow, "J").Address()).Value = .Range(Cells(i, "F").Address(), Cells(i, "K").Address()).Value
End If
Next i
End With
With Sheets("Partlists")
LR = .Cells(Rows.Count, "A").End(xlUp).Row 'last row
For i = 3 To LR
If IsNumeric(Application.Match(.Cells(i, "A").Value, LookUpListInput, 0)) Then
lngNextRow = Sheets("Picklist").Range("A" & Rows.Count).End(xlUp).Row + 1
Sheets("Picklist").Range(Cells(lngNextRow, "A").Address(), Cells(lngNextRow, "E").Address()).Value = .Range(Cells(i, "C").Address(), Cells(i, "G").Address()).Value
Matchres = Application.Match(.Cells(i, "A").Value, LookUpListInput, 0)
Sheets("Picklist").Cells(lngNextRow, "E") = Sheets("Input").Cells(Matchres, "F") * .Cells(i, "G") 'Multiply row from lookuplist column E with .Cells(i, "G")
Sheets("Picklist").Range(Cells(lngNextRow, "F").Address(), Cells(lngNextRow, "J").Address()).Value = Sheets("Input").Range(Cells(Matchres, "G").Address(), Cells(Matchres, "K").Address()).Value 'Copy row from lookuplist column G:K
End If
Next i
End With
Sheets("Input").Range("A5:K138").ClearContents
End Sub
First
Dim Matchres As Variant
and calling it
Matchres = Application.Match(.Cells(i, "A").Value, LookUpListInput, 0)
Does the trick

How to get the sum of two adjacent columns into one merged cell (VBA)?

I am creating a summary macro and I need to add up all the values of column C and D into the merged cell in E. In the image attached the sums are already placed to show the result I want. I already have code to merge the cells in column E based on the names in A. IE Sum up all overdue and critical for bob and place in merged column, then nick. Here is what I have I just need help getting the sum:
Sub MergeSameCell()
Dim Rng As Range, xCell As Range
Dim xRows As Integer
Set WorkRng = ThisWorkbook.Worksheets("Summary").Range("A:A")
lastRow = ActiveSheet.Columns("A").Cells.Find("*", SearchOrder:=xlByRows,
LookIn:=xlValues, SearchDirection:=xlPrevious).Row
xRows = lastRow
For Each Rng In WorkRng.Columns
For i = 1 To xRows - 1
For j = i + 1 To xRows
If Rng.Cells(i, 1).Value <> Rng.Cells(j, 1).Value Then
Exit For
End If
Next
WorkRng.Parent.Range(Rng.Cells(i, 5), Rng.Cells(j - 1, 5)).Merge
i = j - 1
Next
Next
End Sub
The below uses your enclosed data specifically and assumes the data has already been sorted by column A and the cells in column E are already merged.
Public Sub GroupSum()
Dim i0 As Long, i1 As Long, strName As String
With ActiveSheet
For i0 = 2 To .UsedRange.Rows.Count
If Not .Cells(i0, 1).Value = strName Then
strName = .Cells(i0, 1)
i1 = i0
End If
.Cells(i1, 5).Value = .Cells(i0, 3).Value + .Cells(i0, 4).Value + .Cells(i1, 5).Value
Next i0
End With
End Sub
I will leave the alignment formatting of the merged cells to you.
Option Explicit
Sub MergeSameCell()
Dim clientRng As Range
Dim lastRow As Long, lastClientRow As Long
With ThisWorkbook.Worksheets("Summary")
.Columns(5).UnMerge
Set clientRng = .Range("A2")
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Do
lastClientRow = .Columns(1).Find(what:=clientRng.Value, after:=clientRng, _
lookat:=xlWhole, SearchDirection:=xlPrevious).Row
With clientRng.Offset(0, 4)
.Resize(lastClientRow - clientRng.Row + 1, 1).Merge
.Formula = "=sumifs(c:c, a:a, " & Chr(34) & clientRng.Value2 & Chr(34) & ")+" & _
"sumifs(d:d, a:a, " & Chr(34) & clientRng.Value2 & Chr(34) & ")"
'optionally revert the formulas to their returned value
'value = .value2
End With
Set clientRng = clientRng.Offset(lastClientRow - clientRng.Row + 1, 0)
Loop While clientRng.Row <= lastRow
End With
End Sub
This removes a couple of loops:
Sub MergeSameCell()
With ThisWorkbook.Worksheets("Summary")
Dim i as Long
For i = 2 To .Rows.Count
If .Cells(i, 1) = "" Then Exit Sub
Dim x As Long
x = .Evaluate("MATCH(TRUE," & .Cells(i, 1).Address & "<>" & .Range(.Cells(i, 1), .Cells(.Rows.Count, 1)).Address & ",0) - 2 + " & i)
.Cells(i, 5).Value = Application.Sum(.Range(.Cells(i, 3), .Cells(x, 4)))
.Range(.Cells(i, 5), .Cells(x, 5)).Merge
i = x
Next i
End With
End Sub

Resources