Insert "one" blank row every "variable" number of rows - including LOOP? - vba

can anyone advise how can I turn RowIncrement = 2 into a "loop" that goes and pick ups the values from a column based on the other sheet? So, if the first value in the column is 1 then RowIncrement = 1, then it goes to the next value in that column, which may be e.g. 6 and then RowIncrement = 6 and so on.
Sub EmptyRowEveryX()
Dim NumRowsToInsert As Long
Dim RowIncrement As Long
Dim ws As Excel.Worksheet
Dim LastRow As Long
Dim LastEvenlyDivisibleRow
Dim i As Long
Dim z As Long
Dim HowMany As Integer
NumRowsToInsert = 1
RowIncrement = 2
Set ws = ActiveSheet
For n = LastRow To 1 Step -1
HowMany = Range("BM" & z)
If (HowMany > 1) Then
Rows(z & ":" & HowMany).Insert Shift:=xlDown
End If
With ws
LastRow = .Range("AZ" & .Rows.count).End(xlUp).Row
LastEvenlyDivisibleRow = Int(LastRow / RowIncrement) * RowIncrement
If LastEvenlyDivisibleRow = 0 Then
Exit Sub
End If
For i = LastEvenlyDivisibleRow To 1 Step -RowIncrement
.Range(i & ":" & i + (NumRowsToInsert - 1)).Insert xlShiftDown
Next i
End With
Application.ScreenUpdating = True
End Sub

Sub OneEmptyRow()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
With Range("AZ1", Range("AZ" & Rows.count).End(xlUp))
.Subtotal GroupBy:=1, Function:=xlSum, TotalList:=Array(1), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True
.Offset(, -1).AutoFilter Field:=1, Criteria1:="=*total*"
.Offset(2).SpecialCells(xlCellTypeVisible).ClearContents
.AutoFilter
.Offset(, -1).EntireColumn.Delete
.EntireColumn.RemoveSubtotal
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

Related

Excel VBA Find Row, copy contents, paste in next sheet then delete original data

I'm working to identify rows in sheet 1 that are not blank in column A and don't have a Y or L in column V. Then I need to copy the contents of that row, then paste values to an open row on the next worksheet. Lastly, I need to clear contents on the original sheet for that row. I'm getting stuck when it comes time to paste. Error 1004 - Method 'Range' of object'_Worksheet' failed. I appreciate any help.
Option Explicit
Option Compare Text
Sub EndMove()
Dim rowCount As Long, i As Long
Dim ws As Worksheet: Set ws = ActiveSheet
ws.Range("A11").Select
rowCount = ws.Cells(ws.Rows.Count, 1).End(xlUp).row
Application.ScreenUpdating = False: Application.EnableEvents = False
Call ShowAllRecords
For i = 11 To rowCount
If ws.Range("V" & i) <> "y" And ws.Range("V" & i) <> "l" Then
If ws.Range("A" & i) <> "" Then
Dim rowCount2 As Long, j As Long
Dim sRng As Range
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets(ActiveSheet.Index + 1)
Dim wAct As Worksheet
Dim lRow As Long
Dim End_Row As Long
Set wAct = ws
Set sRng = ws.Range("V" & i)
If Not IsDate("01 " & wAct.Name & " 2017") Or wAct.Name = "Dec" Then MsgBox "Not applicable for this sheet.": Exit Sub
If ActiveSheet.Index = ThisWorkbook.Worksheets.Count Then MsgBox "This is the last worksheet cannot move forward.": Exit Sub
wAct.unprotect
With ws2
.unprotect
If rowCount2 = "1" Then
For j = 11 To Rows.Count
If .Range("A" & j) = "" Then
End_Row = j
Exit For
End If
Next j
Else
End If
wAct.Range("A" & sRng.row & ":AD" & sRng.row + sRng.Rows.Count - 1).Copy
.Range("A" & End_Row).PasteSpecial xlPasteValuesAndNumberFormats
wAct.Range("A" & sRng.row & ":AD" & sRng.row + sRng.Rows.Count - 1).ClearContents
.Range("A1000").Value = End_Row
.protect DrawingObjects:=True, Contents:=True, Scenarios:=True, AllowFiltering:=True
End With
wAct.protect DrawingObjects:=True, Contents:=True, Scenarios:=True, AllowFiltering:=True
Application.CutCopyMode = False
End If
End If
Next i
Application.EnableEvents = True: Application.ScreenUpdating = True
Call FilterBlanks
MsgBox "Move Complete"
End If
End Sub
It seems there is no line in your code that would assign value to rowCount2. So when you check it in code below it gives always false and therefore skips this part
If rowCount2 = "1" Then
For j = 11 To Rows.Count
If .Range("A" & j) = "" Then
End_Row = j
Exit For
End If
Next j
Else
but that part is essential as it is the only part where End_Row is assigned value. So then when you try to do this .Range("A" & End_Row) there is nothing in End_Row. Set up a breakpoint on that line and check Locals screen for End_Row to make sure it is this.

Copy cells from a specific column to another worksheet based on criteria

I have two worksheets, "Signed" and "April". I want to copy Column "Y" from "Signed" based on certain criteria into column "A" of "April" starting from the next available/blank row. ( so right under the existing data).
My criteria for column Y is that if column L = month of cell "D2" from "April" AND the year of cell "D2" from "ApriL"...( so right now D2 is 4/30/2017).. then copy that cell in the next available row of Col A of "April" and keep adding on.
I've been trying several different things but just am not able to get it..any idea on how I can achieve this?
My code is below:
Set sourceSht = ThisWorkbook.Worksheets("Signed")
Set myRange = sourceSht.Range("Y1", Range("Y" & Rows.Count).End(xlUp))
Set ws2 = Sheets(NewSheet)
DestRow = ws2.Cells(Rows.Count, "A").End(xlUp).Row + 1
For Each rw In myRange.Rows
If rw.Cells(12).Value = "Month(Sheets(ws2).Range("D2"))" Then
myRange.Value.Copy Destinations:=Sheets(ws2).Range("A" & DestRow)
End If
Something like this should work for you:
Sub tgr()
Dim wb As Workbook
Dim wsData As Worksheet
Dim wsDest As Worksheet
Dim aData As Variant
Dim aResults() As Variant
Dim dtCheck As Date
Dim lCount As Long
Dim lResultIndex As Long
Dim i As Long
Set wb = ActiveWorkbook
Set wsData = wb.Sheets("Signed") 'This is your source sheet
Set wsDest = wb.Sheets("April") 'This is your destination sheet
dtCheck = wsDest.Range("D2").Value2 'This is the date you want to compare against
With wsData.Range("L1:Y" & wsData.Cells(wsData.Rows.Count, "L").End(xlUp).Row)
lCount = WorksheetFunction.CountIfs(.Resize(, 1), ">=" & DateSerial(Year(dtCheck), Month(dtCheck), 1), .Resize(, 1), "<" & DateSerial(Year(dtCheck), Month(dtCheck) + 1, 1))
If lCount = 0 Then
MsgBox "No matches found for [" & Format(dtCheck, "mmmm yyyy") & "] in column L of " & wsData.Name & Chr(10) & "Exiting Macro"
Exit Sub
Else
ReDim aResults(1 To lCount, 1 To 1)
aData = .Value
End If
End With
For i = 1 To UBound(aData, 1)
If IsDate(aData(i, 1)) Then
If Year(aData(i, 1)) = Year(dtCheck) And Month(aData(i, 1)) = Month(dtCheck) Then
lResultIndex = lResultIndex + 1
aResults(lResultIndex, 1) = aData(i, UBound(aData, 2))
End If
End If
Next i
wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Offset(1).Resize(lCount).Value = aResults
End Sub
Alternate method using AutoFilter instead of iterating over an array:
Sub tgrFilter()
Dim wb As Workbook
Dim wsData As Worksheet
Dim wsDest As Worksheet
Dim dtCheck As Date
Set wb = ActiveWorkbook
Set wsData = wb.Sheets("Signed") 'This is your source sheet
Set wsDest = wb.Sheets("April") 'This is your destination sheet
dtCheck = wsDest.Range("D2").Value2 'This is the date you want to compare against
With wsData.Range("L1:Y" & wsData.Cells(wsData.Rows.Count, "L").End(xlUp).Row)
.AutoFilter 1, , xlFilterValues, Array(1, Format(WorksheetFunction.EoMonth(dtCheck, 0), "m/d/yyyy"))
Intersect(.Cells, .Parent.Columns("Y")).Offset(1).Copy wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Offset(1)
.AutoFilter
End With
End Sub
Here's a generic script which you can easily modify to handle almost ANY criteria, as needed.
Sub Copy_If_Criteria_Met()
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
I = Worksheets("Sheet1").UsedRange.Rows.Count
J = Worksheets("Sheet2").UsedRange.Rows.Count
If J = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Sheet2").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("Sheet1").Range("A1:A" & I)
On Error Resume Next
Application.ScreenUpdating = False
For Each xCell In xRg
If CStr(xCell.Value) = "X" Then
xCell.EntireRow.Copy Destination:=Worksheets("Sheet2").Range("A" & J + 1)
xCell.EntireRow.Delete
J = J + 1
End If
Next
Application.ScreenUpdating = True
End Sub

speed up the processing of excel vba

I've created excel vba file. However, it takes very long time to run the whole file because the total of the rows is up to 270,000 lines. Does anyone know how can I speed up the running process? Any help would be much appreciated. Thanks in advance.
Sub datemodifiedFile()
Dim File1 As Object
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set File1 = fso.getfile("C:\Users\Meg\Desktop\Master File.xlsx")
If Sheets("today").Range("B1").Value = File1.DateLastModified Then
Else
Sheets("today").Range("B1").Value = File1.DateLastModified
Dim WbB As Workbook
Set WbB = Workbooks.Open(Filename:="C:\Users\Meg\Desktop\Master File.xlsx", ReadOnly:=True)
Dim SheetB As Worksheet
Dim lastrow As Long
Set SheetB = WbB.Sheets("Sheet1")
SheetB.Select
Rows("1:1").Select
'Selection.AutoFilter
'ActiveSheet.Range("A:V").AutoFilter Field:=20, Criteria1:=""
Columns("A:V").Select
Selection.Copy
ThisWorkbook.Activate
Sheets("today").Select
Range("C1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'Columns("A:X").Select
'ActiveSheet.Range("$A$1:$X$750001").RemoveDuplicates Columns:=Array(3, 4, 6), _
Header:=xlYes
Application.CutCopyMode = False
lastrow = Sheets("today").Range("D" & Rows.Count).End(xlUp).Row
Sheets("today").Cells(lastrow, 3).EntireRow.Delete
WbB.Close False
End If
End Sub
Sub dltnew()
Dim i As Long
Dim lrow As Long
lrow = Sheets("today").Range("C" & Rows.Count).End(xlUp).Row
For i = 2 To lrow
If Sheets("today").Cells(i, 2).Value = "NEW" Then
Sheets("today").Cells(i, 2).Value = ""
Sheets("today").Cells(i, 1).Value = ""
End If
Next i
End Sub
Sub comdate()
Dim Sheet1 As Worksheet
Dim Sheet3 As Worksheet
Dim lrow As Long
Dim i As Long
Set Sheet1 = ThisWorkbook.Sheets("main")
Set Sheet3 = ThisWorkbook.Sheets("today")
Sheet3.Range("A1").Value = Date
Sheet3.Range("A1").NumberFormat = "dd/mm/yyyy"
Sheet3.Range("A1").Font.Color = Sheet3.Range("A1").Interior.Color
Sheet3.Columns("A:A").EntireColumn.Hidden = False
If Sheet1.Range("B1").Value <> Sheet3.Range("A1").Value Then
Sheet1.Range("B1").Value = Sheet3.Range("A1").Value
lrow = Sheet1.Range("C" & Rows.Count).End(xlUp).Row
For i = 2 To lrow
If Sheet1.Cells(i, 2).Value = "NEW" Then
Sheet1.Cells(i, 2).Value = ""
End If
Next i
End If
End Sub
Sub Con()
Dim LasRow As Long
Application.ScreenUpdating = False
LasRow = Sheets("today").Range("C" & Rows.Count).End(xlUp).Row
Sheets("today").Range("A2:A" & LasRow).Formula = "=C2&G2&I2"
ActiveSheet.AutoFilterMode = False
Application.ScreenUpdating = True
End Sub
Sub Compare()
Dim mrow As Range, trow As Long
With Worksheets("main")
Set mrow = .Range("A2", .Range("A" & Rows.Count).End(xlUp))
End With
trow = Worksheets("today").Range("A" & Rows.Count).End(xlUp).Row
With Worksheets("today")
For j = 2 To trow
If mrow.Find(What:=.Range("A" & j).Value, LookIn:=xlValues, LookAt:=xlWhole) Is Nothing _
Then .Range("B" & j).Value = "NEW"
Next j
End With
End Sub
Sub getnew()
Dim Sheet1 As Worksheet
Dim Sheet3 As Worksheet
Dim lastrow As Long
Dim i As Long
Dim erow As Long
Set Sheet1 = ThisWorkbook.Sheets("main")
Set Sheet3 = ThisWorkbook.Sheets("today")
lastrow = Sheet3.Range("C" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow
If Sheet3.Cells(i, 2).Value = "NEW" Then
erow = Sheet1.Range("C" & Rows.Count).End(xlUp).Row + 1
Sheet3.Cells(i, 2).EntireRow.Copy Destination:=Sheet1.Range("A" & erow)
Application.CutCopyMode = False
Sheet1.Select
Range("A1:X750001").Select
Selection.Sort Key1:=Range("G2"), Order1:=xlAscending, Key2:=Range("C2") _
, Order2:=xlAscending, Header:=xlGuess, OrderCustom:=1, MatchCase:= _
False, Orientation:=xlTopToBottom
End If
Next i
End Sub
Sub hidecellvalue()
Dim Sheet1 As Worksheet
Dim lastrow As Long
Dim k As Long
Set Sheet1 = ThisWorkbook.Sheets("main")
lastrow = Sheet1.Range("B" & Rows.Count).End(xlUp).Row
For k = 2 To lastrow
If Sheet1.Cells(k, 1).Value <> "NEW" Then
Sheet1.Cells(k, 1).Font.Color = Sheet1.Cells(k, 1).Interior.Color
'Sheet1.Columns("A:A").EntireColumn.Hidden = False
End If
Next k
End Sub
Sub hideSh1column()
Dim Sheet1 As Worksheet
Set Sheet1 = ThisWorkbook.Sheets("main")
Sheet1.Columns("A:A").EntireColumn.Hidden = True
Sheet1.Columns("D:F").EntireColumn.Hidden = True
Sheet1.Columns("H:H").EntireColumn.Hidden = True
Sheet1.Columns("L:L").EntireColumn.Hidden = True
Sheet1.Columns("N:N").EntireColumn.Hidden = True
Sheet1.Columns("P:P").EntireColumn.Hidden = True
End Sub
Sub HideSheet3()
Sheets("today").Visible = xlSheetVisible
End Sub
I would start with remove as much as .activate and select you have in your code and replace it with proper sheet.cell/range selection.
Then i would add this on beggining of your code
Dim previousScreenUpdating As Boolean
previousScreenUpdating = Application.ScreenUpdating
Application.ScreenUpdating = False
Dim previousCalculation As XlCalculation
previousCalculation = Application.Calculation
Application.Calculation = xlCalculationManual
and this on the end of your code
Application.ScreenUpdating = previousScreenUpdating
Application.Calculation = previousCalculation
This should be much faster.
You should always try to do as much using arrays as possible, rather than going through your data cell-by-cell.
In addition, a dictionary-based lookup is always going to beat using Find() when you're checking things in a large loop.
Sub Compare()
Dim mrow As Range, trow As Long, arr, r As Long
Dim d As Object, rngV As Range
Dim arrV, arrN, wsT As Worksheet, wsM As Worksheet
Set d = CreateObject("Scripting.Dictionary")
Set wsM = Worksheets("Main")
Set wsT = Worksheets("today")
'get all unique values in ColA on Main
arr = wsM.Range(wsM.Range("A2"), wsM.Cells(wsM.Rows.Count, 1).End(xlUp)).Value
For r = 1 To UBound(arr, 1)
d(arr(r, 1)) = 1
Next r
Set rngV = wsT.Range(wsT.Range("A2"), wsT.Cells(wsT.Rows.Count, 1).End(xlUp))
arrV = rngV.Value 'values from colA as array
arrN = rngV.Offset(0, 1).Value 'values from colB as array
'check colA against the dictionary and update colB array as needed
For r = 1 To UBound(arrV, 1)
If Not d.exists(arrV(r, 1)) Then arrN(r, 1) = "NEW"
Next r
'repopulate ColB with updated data
rngV.Offset(0, 1).Value = arrN
End Sub

Empty rows not showing as empty rows using CountA

Why does the following VBA script not show any message boxes when row 4, 5 and 6 are all empty...
Sub Test()
LastRow = 40
For i = LastRow To 3 Step -1
Set myRange = Range("B" & i & ":T" & i)
If WorksheetFunction.CountA(myRange) = 0 Then
MsgBox "Empty " & Cells(i, 1).Row
Else
x = x
End If
Next
End Sub
Just test both column ranges:
Sub Test()
LastRow = 40
For i = LastRow To 3 Step -1
count = WorksheetFunction.CountA(Range("B"&i & ":D"&i))
count = count + WorksheetFunction.CountA(Range("F"&i & ":T"&i))
If count = 0 Then
MsgBox "Empty " & i
End If
Next
End Sub
edit: or build a range object which contains the two column ranges, intersect that with the last row, and move this range object in the loop. This way, you don't build the range object anew in each iteration:
Sub Test()
Dim rng As Range, colrng As Range
Dim LastRow As Long
Dim i As Long
LastRow = 40
Set colrng = Application.Union(Range("B:D"), Range("F:T"))
Set rng = Application.Intersect(colrng, Rows(LastRow))
For i = LastRow To 3 Step -1
If WorksheetFunction.CountA(rng) = 0 Then
MsgBox "Empty row: " & i
End If
Set rng = rng.Offset(-1, 0)
Next
End Sub
As good practice, always declare your variables, and use long integers for row or column indices.
Sub Test()
LastRow = 40
For i = LastRow To 3 Step -1
Set myRange = Range("B" & i & ":T" & i)
If WorksheetFunction.CountIf(myRange,"<>") = 0 Then 'count where it's not a null or empty string
MsgBox "Empty " & Cells(i, 1).Row
Else
x = x
End If
Next
End Sub
The only way I can seem to do it is a slow way:
LastRow = Range("B:Z").Find(What:="*", LookIn:=xlValues, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastColumn = Cells.Find(What:="*", LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
For i = LastRow To 3 Step -1
BlankRow = False
For j = 2 To LastColumn
If Cells(i, j).Value <> "" Then
Blank = False
Exit For
End If
BlankRow = True
Next j
If BlankRow = True Then
x = x
End If
Next i

Delete rows until cell = "Total"

I would like to with this macro delete all cells after last empty row until the line where in column "E" is "Total"
I've tried this, but there is error on loop line:
Sub delete()
Dim r As Range
Dim lastRow As Long
Dim c As Range
Dim i As Long
i = lastRow + 1
With ThisWorkbook.Worksheets("Sheet1")
lastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
End With
Do
Set r = Range("B" & i)
If Len(r) = 0 Then r.EntireRow.delete
i = i + 1
Loop Until Cells(i, 5).Value = "Total"
End Sub
And here is the example how my table look like:
I'd use something like the following which will continue through all cells until E&i = total:
Public Sub Delete()
Dim i As Long
i = 2 'Start from row 2
Application.ScreenUpdating = False
With ThisWorkbook.Worksheets("Sheet1")
Do Until .Range("E" & i).Value = "Total"
If .Range("B" & i).Value = vbNullString Then
.Rows(i).EntireRow.Delete
Else
i = i + 1 'Only increment if the row hasn't been deleted to prevent skipping rows
End If
Loop
End With
Application.ScreenUpdating = True
End Sub