I want to copy the last row that that has formulas from a worksheet to the next row down and then value out the row that I just copied down. For example I have formulas in columns A through W and my current last row is 10 and I want to copy row 10 to row 11 and then value out row 10. Trying to get vba code to automate process. Any help appreciated.
This should get you started in the right direction:
Sub appendToEnd()
Dim myLastCell As Range
Set myLastCell = LastCell(Worksheets("Sheet1").Range("A:W"))
Dim lastCellCoords As String: lastCellCoords = "A" & myLastCell.Row & ":W" & myLastCell.Row
Dim firstEmptyRow As Integer: firstEmptyRow = myLastCell.Row + 1
Dim firstEmptyCoords As String: firstEmptyCoords = "A" & firstEmptyRow & ":W" & firstEmptyRow
If Not myLastCell Is Nothing Then
' Now Copy the range:
Worksheets("Sheet1").Range(lastCellCoords).Copy
' And paste to first empty row
Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Else
MsgBox ("There is no data in specified range")
End If
End Sub
Function LastCell(r As Range) As Range
'
' Note "&" denotes a long value; "%" denotes an integer value
Dim LastRow&, lastCol%
On Error Resume Next
With r
' Find the last real row
LastRow& = .Cells.Find(What:="*", _
SearchDirection:=xlPrevious, _
SearchOrder:=xlByRows).Row
' Find the last real column
lastCol% = .Cells.Find(What:="*", _
SearchDirection:=xlPrevious, _
SearchOrder:=xlByColumns).Column
End With
' Finally, initialize a Range object variable for
' the last populated row.
Set LastCell = r.Cells(LastRow&, lastCol%)
End Function
Related
Below is the code which i gave written to search for the comment in the excel worksheet, the comments contains special characters too. can anyone help me to get rid of the type mismatch error. Below it the code which i am pasting for the reference
Option Explicit
Sub Match_ProjCode()
Dim CSAT_Comments As Workbook
Dim comment As Worksheet
Dim matchcomment As Worksheet
Dim comment_string As String 'To store the comment
Dim Column As Integer
Dim Row As Integer
Dim match_Row As Integer
Dim comments_Column_Name As String '
Dim Comments_Column_Value As String
Dim Comments_ProjCode As String 'To store the project code
Dim RangeObj As Range
Set CSAT_Comments = ActiveWorkbook
Set comment = CSAT_Comments.Worksheets("Qualitative Analysis_2018 Cycle") '
Set matchcomment = CSAT_Comments.Worksheets("Consolidated Comments") '
Dim range1 As Range
Dim rng As Range
matchcomment.Range("A2").Select
Set range1 = matchcomment.Range(Selection, Selection.End(xlDown))
For Each rng In range1.SpecialCells(xlCellTypeVisible)
comment_string = rng.Value ' Comment text will be stored
match_Row = rng.Row 'comment row will be stored
With comment
.Activate
Columns("AK:BL").Select
Set RangeObj = Selection.Find(What:=comment_string, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False) ' to search for the comment in the comment worksheet
If Not RangeObj Is Nothing Then
.Range(RangeObj.Address).Select 'Select the cell of the searched value
Column = ActiveCell.Column 'Get the column number of the searched value
Row = ActiveCell.Row ' Get the row number of the searched value
comments_Column_Name = Split(Cells(, Column).Address, "$")(1) ' Trim the column name from the cell address
Comments_Column_Value = .Range("" & comments_Column_Name & 1) ' Get the comment heading
Comments_ProjCode = .Range("A" & Row) 'Get the project code
With matchcomment
.Activate
.Range("C" & match_Row) = Comments_Column_Value ' Paste the comment heading name in the match sheet
.Range("D" & match_Row) = Comments_ProjCode 'Paste the project code in the match sheet
End With
Else
End If
End With
Next rng
End Sub
the issue is that Find() has a 255 length limit
you could get around it as follows:
For Each rng In range1.SpecialCells(xlCellTypeVisible)
comment_string = Left(rng.Value, 255) ' <<<<Comment text will be stored up to 255 length
match_Row = rng.Row 'comment row will be stored
With comment
.Activate
Columns("AK:BL").Select
Set RangeObj = Selection.Find(What:=comment_string, After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False) ' to search for the comment in the comment worksheet
If Not RangeObj Is Nothing Then
If RangeObj.Text = rng.Value Then '<<<< be sure the whole text matches
.Range(RangeObj.Address).Select 'Select the cell of the searched value
Column = ActiveCell.Column 'Get the column number of the searched value
Row = ActiveCell.Row ' Get the row number of the searched value
comments_Column_Name = Split(Cells(, Column).Address, "$")(1) ' Trim the column name from the cell address
Comments_Column_Value = .Range("" & comments_Column_Name & 1) ' Get the comment heading
Comments_ProjCode = .Range("A" & Row) 'Get the project code
With matchcomment
.Activate
.Range("C" & match_Row) = Comments_Column_Value ' Paste the comment heading name in the match sheet
.Range("D" & match_Row) = Comments_ProjCode 'Paste the project code in the match sheet
End With
Else
End If
End If
End With
Next rng
When you are not using Option Explicit and this is where the problems start. The RangeObj is not declared, hence VBA "declares" it as a Variant. However, it should be at least an Object and an Object of type Range, if possible.
Thus, to make sure that the code works further, declare the RangeObj explicitly like this:
Dim RangeObj as Range
To make sure that every variable is declared explicilty, write Option Explicit on the top of the module.
Option Explicit MSDN Reference
I am trying to come up with a macro that checks if any numeral value exists in a cell. If a numeral value exists, copy a portion of that row and paste it into another worksheet within the same spreadsheet.
Sheet1 is the sheet that has all my data in it. I am trying to look in column R if there is any values in it. If it does, copy that cell and the four adjacent cells to the left of it and paste it into Sheet2.
This is what I have come up with so far based on mish-mashing other people's code though it only does a part of what I want. It just copies part of a row then pastes it into another worksheet but it does not check column R for a value first. It just copies and pastes regardless and does not move onto the next row once it has done that. I need it to continue onto the next row to continue looking:
Sub Paste_Value_Test()
Dim c As Range
Dim IRow As Long, lastrow As Long
Dim rSource As Range
Dim wsI As Worksheet, wsO As Worksheet
On Error GoTo Whoa
'~~> Sheet Where values needs to be checked
Set wsI = ThisWorkbook.Sheets("Sheet1")
'~~> Output sheet
Set wsO = ThisWorkbook.Sheets("Sheet2")
Application.ScreenUpdating = False
With wsI
'~~> Find Last Row which has data in Col O to R
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lastrow = .Columns("O:R").Find(What:="*", _
After:=.Range("O3"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lastrow = 1
End If
'~~> Set you input range
Set rSource = .Range("R" & lastrow)
'~~> Search for the cell which has "L" and then copy it across to sheet1
For Each c In rSource
Debug.Print cValue
If c.Value > "0" Then
.Range("O" & c.Row & ":R" & c.Row).Copy
wsO.Cells(5 + IRow, 12).PasteSpecial Paste:=xlPasteValues
IRow = IRow + 1
End If
Next
End With
LetsContinue:
Application.ScreenUpdating = True
Application.CutCopyMode = False
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
Below is some code which hopefully achieves what I think you are trying to do. I have included comments throughout stating what I changed:
Sub Paste_Value_Test()
Dim c As Range
Dim IRow As Long, lastrow As Long
Dim rSource As Range
Dim wsI As Worksheet, wsO As Worksheet
On Error GoTo Whoa
'~~> Sheet Where values needs to be checked
Set wsI = ThisWorkbook.Sheets("Sheet1")
'~~> Output sheet
Set wsO = ThisWorkbook.Sheets("Sheet2")
Application.ScreenUpdating = False
With wsI
'~~> Find Last Row which has data in Col O to R
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
'You specified "After" to be cell O3. This means a match will
' occur on row 2 if cell R2 (or O2 or P2) has something in it
' because cell R2 is the cell "after" O3 when
' "SearchDirection:=xlPrevious"
' After:=.Range("O3"), _
lastrow = .Columns("O:R").Find(What:="*", _
After:=.Range("O1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lastrow = 1
End If
'This was only referring to the single cell in column R on the
' last row (in columns O:R)
'Set rSource = .Range("R" & lastrow)
'Create a range referring to everything in column R, from row 1
' down to the "last row"
Set rSource = .Range("R1:R" & lastrow)
'This comment doesn't seem to reflect what the code was doing, or what the
'question said
'~~> Search for the cell which has "L" and then copy it across to sheet1
For Each c In rSource
'This is printing the variable "cValue", which has never been set
'Debug.Print cValue
'It was probably meant to be
Debug.Print c.Value
'This was testing whether the value in the cell was
' greater than the string "0"
'So the following values would be > "0"
' ABC
' 54
' ;asd
'And the following values would not be > "0"
' (ABC)
' $523 (assuming that was as text, and not just 523 formatted as currency)
'If c.Value > "0" Then
'I suspect you are trying to test whether the cell is numeric
' and greater than 0
If IsNumeric(c.Value) Then
If c.Value > 0 Then
'This is only copying the cell and the *three* cells
' to the left of it
'.Range("O" & c.Row & ":R" & c.Row).Copy
'This will copy the cell and the *four* cells
' to the left of it
'.Range("N" & c.Row & ":R" & c.Row).Copy
'wsO.Cells(5 + IRow, 12).PasteSpecial Paste:=xlPasteValues
'But this would avoid the use of copy/paste
wsO.Cells(5 + IRow, 12).Resize(1, 5).Value = _
.Range("N" & c.Row & ":R" & c.Row).Value
IRow = IRow + 1
End If
End If
Next
End With
LetsContinue:
Application.ScreenUpdating = True
Application.CutCopyMode = False
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
I have a small programme which I want to loop through several worksheets. But the problem is in the code I have, there are variables that needs to be changed from worksheet to worksheet. Therefore I can't use the loop command.
In my code (please see below) I have set them as VARIABLE1, VARIABLE2 etc. The values of these should be changed when it run first time, second time and so on.
Example:
In the First Loop VARIABLE1 should be equal to "CMGLT" and in the
Second Loop VARIABLE1 should be equal to "CMCLT".
Function WorksheetExists(WSName As String) As Boolean
On Error Resume Next
WorksheetExists = Worksheets(WSName).Name = WSName
On Error GoTo 0
End Function
Sub BOI()
If Not WorksheetExists("VARIABLE1") Then '---------------VARIABLE1
Sheets.Add.Name = "VARIABLE1" '---------------VARIABLE1
Else
'START GEN CODE
'Set CMGLT as activesheet!!!!
Worksheets("VARIABLE1").Activate '---------------VARIABLE1
'Checking company code
Dim celltxt As String
celltxt = ActiveSheet.Range("G8").Text
If InStr(1, celltxt, "VARIABLE2") Then '---------------VARIABLE2
'unmerge entire sheet
ActiveSheet.Cells.UnMerge
'unwrap entire sheet
ActiveSheet.Cells.WrapText = False
'set short date format for up to 3000 rows
ActiveSheet.Range("A2", "A3000").NumberFormat = "dd/mm/yyyy"
'delete blank rows in column A
Range("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
'delete rows from 1 to 6
Rows("1:6").EntireRow.Delete
'deleting all rows below "total"
Dim LR As Long, Found As Range
LR = Range("A" & Rows.Count).End(xlUp).Row
Set Found = Columns("A").Find(What:="Total", LookIn:=xlValues, lookat:=xlWhole)
If Not Found Is Nothing Then Rows(Found.Row & ":" & LR).Delete
'changing column width of B column
Range("B1").ColumnWidth = 12
'changing column width of A column
Range("A1").ColumnWidth = 12
'changing formating of B column to General
Range("B:B").NumberFormat = "General"
'CHANGE THIS AS APPROPRIATELY!!!!
Range("B1").Value = "VARIABLE3" '------------------------------------'VARIABLE3
'getting date as value
Range("C1").Select
ActiveCell.FormulaR1C1 = "=TEXT(RC[-2],""DD.MM.YYYY"")"
'copying company code and date until last row of data
Dim LRow As Long
LRow = ActiveSheet.UsedRange.Rows.Count
Range("B1").AutoFill Destination:=Range("B1:B" & LRow)
Range("C1").AutoFill Destination:=Range("C1:C" & LRow)
'pasting date as value
Columns("C:C").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
'deleting blank rows in amount column
On Error Resume Next
Range("W:W").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
'coping data to "UP" sheet
Dim Lastrow As Integer
Lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Range("C1:C" & Lastrow).Copy Destination:=Worksheets("Up").Range("A" & Rows.Count).End(xlUp).Offset(1)
Range("B1:B" & Lastrow).Copy Destination:=Worksheets("Up").Range("C" & Rows.Count).End(xlUp).Offset(1)
Range("C1:C" & Lastrow).Copy Destination:=Worksheets("Up").Range("D" & Rows.Count).End(xlUp).Offset(1)
Range("Q1:Q" & Lastrow).Copy Destination:=Worksheets("Up").Range("F" & Rows.Count).End(xlUp).Offset(1)
Range("Q1:Q" & Lastrow).Copy Destination:=Worksheets("Up").Range("I" & Rows.Count).End(xlUp).Offset(1)
Range("W1:W" & Lastrow).Copy Destination:=Worksheets("Up").Range("O" & Rows.Count).End(xlUp).Offset(1)
'END GEN CODE
Else
MsgBox ("VARIABLE1 Validation Mismatch. Exiting...") '---------------VARIABLE1
Exit Sub
End If
End If
End Sub
edited for some code speed improvements after OP's sharing an example file
you can have your BOI sub accept varying strings as parameters and be called by a main sub looping through all of them
like follows
Option Explicit
Sub main() '<~~ main sub calling BOI inside a loop
Dim VARIABLE1 As Variant, VARIABLE2 As Variant, VARIABLE3 As Variant
Dim i As Long
VARIABLE1 = Array("CMGLT", "CMCLT", "VARIABLE3", "VARIABLE4") '<~~ "main" array containing all VARIABLE1 needed values
VARIABLE2 = Array("114486744", "104074162", "VARIABLE2-3", "VARIABLE2-4") ' <~~ VARIABLE2 array, with elements corresponding by position to VARIABLE1 ones -> total elements number must match VARIABLE1 one
VARIABLE3 = Array("VARIABLE3-1", "VARIABLE3-2", "VARIABLE3-3", "VARIABLE3-4") ' <~~ VARIABLE3 array, with elements corresponding by position to VARIABLE1 ones -> total elements number must match VARIABLE1 one
For i = 0 To UBound(VARIABLE1) ' <~~ loop over your VARIABLE1 array
Call BOI(VARIABLE1(i), VARIABLE2(i), VARIABLE3(i)) ' <~~ and pass VARIABLE2 and VARIABLE3 corresponding elements, too
Next i
End Sub
Sub BOI(VARIABLE1 As Variant, VARIABLE2 As Variant, VARIABLE3 As Variant)
Dim LR As Long
Dim found As Range
If Not WorksheetExists(CStr(VARIABLE1)) Then '---------------VARIABLE1
Sheets.Add.Name = CStr(VARIABLE1)
Else
'START GEN CODE
With Worksheets(CStr(VARIABLE1)) '---------------VARIABLE1 '<~~ instead of selecting/activating wanted sheet, tell VBA to consider it as implicit object for any subsequent methods or properties calls
'Checking company code
If InStr(1, .Range("G8"), CStr(VARIABLE2)) Then '---------------VARIABLE2
'unmerge entire sheet
.UsedRange.UnMerge '<~~ VBA reads this statement as "Worksheets(CStr(VARIABLE1)).UsedRange.Unmerge"
'unwrap entire sheet
.UsedRange.WrapText = False '<~~ act on usedrange only, to be faster
LR = .Range("A" & .Rows.Count).End(xlUp).Row '<~~ store last non empty row index
'clearing all rows below "Total"
Set found = .Range("A2:A" & LR).SpecialCells(xlCellTypeConstants, xlTextValues).Find(what:="Total", LookIn:=xlValues, lookat:=xlWhole) '<~~ search into relevant cells only
If Not found Is Nothing Then .Rows(found.Row & ":" & LR).Clear '<~~ Clear() is faster then Delete()
'set short date format for up to 3000 rows
LR = .Range("A" & .Rows.Count).End(xlUp).Row '<~~ update last non empty row index (you possibly deleted some rows before)
' .Range("A2", "A3000").NumberFormat = "dd/mm/yyyy"
.Range("A2:A" & LR).SpecialCells(xlCellTypeConstants, xlNumbers).NumberFormat = "dd/mm/yyyy" '<~~ act on relevant cells only
'delete blank rows in column A
.Range("A1:A" & LR).SpecialCells(xlCellTypeBlanks).EntireRow.Delete '<~~ avoid deleting blank rows after the last non empty one
'delete rows from 1 to 6
.Rows("1:6").EntireRow.Delete
LR = .Range("A" & .Rows.Count).End(xlUp).Row '<~~ update last non empty row index (you possibly deleted some rows before)
'changing column width of B column
.Range("B1").ColumnWidth = 12
'changing column width of A column
.Range("A1").ColumnWidth = 12
'changing formating of B column to General
.Range("B1:B" & LR).NumberFormat = "General" '<~~ act on relevant cells only
'CHANGE THIS AS APPROPRIATELY!!!!
.Range("B1").Value = VARIABLE3 '------------------------------------'VARIABLE3
'getting date as value
.Range("C1").FormulaR1C1 = "=TEXT(RC[-2],""DD.MM.YYYY"")" '<~~ instead of selecting and then acting on selection, just act directly on the range object
'copying company code and date until last row of data
.Range("B1").AutoFill Destination:=Range("B1:B" & LR)
.Range("C1").AutoFill Destination:=Range("C1:C" & LR)
'pasting date as value
' .Columns("C:C").Select
' Selection.Copy
' Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
' :=False, Transpose:=False
' Application.CutCopyMode = False
With .Columns("C:C").SpecialCells(xlCellTypeFormulas) '<~~ this is equivalent to what above, but much faster
.Value = .Value
End With
'deleting blank rows in amount column
On Error Resume Next
.Range("W1:W" & LR).SpecialCells(xlCellTypeBlanks).EntireRow.Delete '<~~ act on relevant cells only
On Error GoTo 0 '<~~ always remember to set standard error trapping right after you don't need skipping errors anymore
'coping data to "UP" sheet
LR = .Cells(Rows.Count, 1).End(xlUp).Row '<~~ update last non empty row index (you possibly deleted some rows before)
CopyValues .Range("C1:C" & LR), Worksheets("Up"), "A" '<~~ take advantage of a sub to avoid repeating same code
CopyValues .Range("B1:B" & LR), Worksheets("Up"), "C" '<~~ take advantage of a sub to avoid repeating same code
CopyValues .Range("C1:C" & LR), Worksheets("Up"), "D" '<~~ take advantage of a sub to avoid repeating same code
CopyValues .Range("Q1:Q" & LR), Worksheets("Up"), "F" '<~~ take advantage of a sub to avoid repeating same code
CopyValues .Range("Q1:Q" & LR), Worksheets("Up"), "I" '<~~ take advantage of a sub to avoid repeating same code
CopyValues .Range("W1:W" & LR), Worksheets("Up"), "O" '<~~ take advantage of a sub to avoid repeating same code
'END GEN CODE
Else
MsgBox (VARIABLE1 & " Validation Mismatch. Exiting...") '---------------VARIABLE1
Exit Sub
End If
End With
End If
End Sub
Sub CopyValues(sourceRng As Range, targetSht As Worksheet, targetCol As String)
With targetSht
.Range(targetCol & .Rows.Count).End(xlUp).Offset(1).Resize(sourceRng.Rows.Count).Value = sourceRng.Value
End With
End Sub
Function WorksheetExists(WSName As String) As Boolean
On Error Resume Next
WorksheetExists = Worksheets(WSName).Name = WSName
On Error GoTo 0
End Function
where I also made some more (of all possible) little code optimizations too
I am trying to write a macro in vba for excel. I want to delete every row that does not have at least one of three keywords in column D (keywords being "INVOICE", "PAYMENT", or "P.O."). I need to keep every row that contains these keywords. All other rows need to be deleted and the rows remaining need to be pushed to the top of the document. There are also two header rows that can not be deleted.
I found the code below but it deletes every row that does not contain "INVOICE" only. I can not manipulate the code to do what I need it to do.
Sub Test()
Dim ws As Worksheet
Dim rng1 As Range
Dim lastRow As Long
Set ws = ActiveWorkbook.Sheets("*Name of Worksheet")
lastRow = ws.Range("D" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("D1:D" & lastRow)
' filter and delete all but header row
With rng
.AutoFilter Field:=1, Criteria1:="<>*INVOICE*"
.Offset(2, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
' turn off the filters
ws.AutoFilterMode = False
End Sub
I would approach this loop slightly different. To me this is a bit easier to read.
Sub Test()
Dim ws As Worksheet
Dim lastRow As Long, i As Long
Dim value As String
Set ws = ActiveWorkbook.Sheets("*Name of Worksheet")
lastRow = ws.Range("D" & ws.Rows.Count).End(xlUp).Row
' Evaluate each row for deletion.
' Go in reverse order so indexes don't get messed up.
For i = lastRow To 2 Step -1
value = ws.Cells(i, 4).Value ' Column D value.
' Check if it contains one of the keywords.
If Instr(value, "INVOICE") = 0 _
And Instr(value, "PAYMENT") = 0 _
And Instr(value, "P.O.") = 0 _
Then
' Protected values not found. Delete the row.
ws.Rows(i).Delete
End If
Next
End Sub
The key here is the Instr function which checks for your protected keywords within the cell value. If none of the keywords are found then the If condition is satisfied and the row is deleted.
You can easily add additional protected keywords by just appending to the If conditions.
'similar with previous post, but using "like" operator
Sub test()
Dim ws As Worksheet, i&, lastRow&, value$
Set ws = ActiveWorkbook.ActiveSheet
lastRow = ws.Range("D" & ws.Rows.Count).End(xlUp).Row
For i = lastRow To 2 Step -1
value = ws.Cells(i, 4).value
' Check if it contains one of the keywords.
If Not (value Like "*INVOICE*" _
Or value Like "*PAYMENT*" _
Or value Like "*P.O.*") _
Then
' Protected values not found. Delete the row.
ws.Rows(i).Delete
End If
Next
End Sub
'
Sub test()
Dim i&
Application.ScreenUpdating = False
i = Range("D" & Rows.Count).End(xlUp).Row
While i <> 1
With Cells(i, 4)
If Not (.value Like "*INVOICE*" _
Or .value Like "*PAYMENT*" _
Or .value Like "*P.O.*") _
Then
Rows(i).Delete
End If
End With
i = i - 1
Wend
Application.ScreenUpdating = True
End Sub
The othe way is to insert an IF test in a working column, and then AutoFilter that.
This is the VBA equivalent of entering
=SUM(COUNTIF(D1,{"*INVOICE*","*PAYMENT*","*P.O.*"}))=0
and then deleting any row where none of these values are found in the corrresponing D cell
Sub QuickKill()
Dim rng1 As Range, rng2 As Range, rng3 As Range
Set rng1 = Cells.Find("*", , xlValues, , xlByColumns, xlPrevious)
Set rng2 = Cells.Find("*", , xlValues, , xlByRows, xlPrevious)
Set rng3 = Range(Cells(rng2.Row, rng1.Column), Cells(1, rng1.Column))
Application.ScreenUpdating = False
Rows(1).Insert
With rng3.Offset(-1, 1).Resize(rng3.Rows.Count + 1, 1)
.FormulaR1C1 = "=SUM(COUNTIF(RC[-1],{""*INVOICE*"",""*PAYMENT*"",""*P.O.*""}))=0"
.AutoFilter Field:=1, Criteria1:="TRUE"
.EntireRow.Delete
On Error Resume Next
'in case all rows have been deleted
.EntireColumn.Delete
On Error GoTo 0
End With
Application.ScreenUpdating = True
End Sub
I would like to delete the empty rows my ERP Quotation generates. I'm trying to go through the document (A1:Z50) and for each row where there is no data in the cells (A1-B1...Z1 = empty, A5-B5...Z5 = empty) I want to delete them.
I found this, but can't seem to configure it for me.
On Error Resume Next
Worksheet.Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
How about
sub foo()
dim r As Range, rows As Long, i As Long
Set r = ActiveSheet.Range("A1:Z50")
rows = r.rows.Count
For i = rows To 1 Step (-1)
If WorksheetFunction.CountA(r.rows(i)) = 0 Then r.rows(i).Delete
Next
End Sub
Try this
Option Explicit
Sub Sample()
Dim i As Long
Dim DelRange As Range
On Error GoTo Whoa
Application.ScreenUpdating = False
For i = 1 To 50
If Application.WorksheetFunction.CountA(Range("A" & i & ":" & "Z" & i)) = 0 Then
If DelRange Is Nothing Then
Set DelRange = Range("A" & i & ":" & "Z" & i)
Else
Set DelRange = Union(DelRange, Range("A" & i & ":" & "Z" & i))
End If
End If
Next i
If Not DelRange Is Nothing Then DelRange.Delete shift:=xlUp
LetsContinue:
Application.ScreenUpdating = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
IF you want to delete the entire row then use this code
Option Explicit
Sub Sample()
Dim i As Long
Dim DelRange As Range
On Error GoTo Whoa
Application.ScreenUpdating = False
For i = 1 To 50
If Application.WorksheetFunction.CountA(Range("A" & i & ":" & "Z" & i)) = 0 Then
If DelRange Is Nothing Then
Set DelRange = Rows(i)
Else
Set DelRange = Union(DelRange, Rows(i))
End If
End If
Next i
If Not DelRange Is Nothing Then DelRange.Delete shift:=xlUp
LetsContinue:
Application.ScreenUpdating = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
I know I am late to the party, but here is some code I wrote/use to do the job.
Sub DeleteERows()
Sheets("Sheet1").Select
Range("a2:A15000").Select
Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End Sub
for those who are intersted to remove "empty" and "blank" rows ( Ctrl + Shift + End going deep down of your worksheet ) .. here is my code.
It will find the last "real"row in each sheet and delete the remaining blank rows.
Function XLBlank()
For Each sh In ActiveWorkbook.Worksheets
sh.Activate
Cells(1, 1).Select
lRow = Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Range("A" & lRow + 1, Range("A1").SpecialCells(xlCellTypeLastCell).Address).Select
On Error Resume Next
Selection.EntireRow.SpecialCells(xlBlanks).EntireRow.Delete
Cells(1, 1).Select
Next
ActiveWorkbook.Save
ActiveWorkbook.Worksheets(1).Activate
End Function
Open VBA ( ALT + F11 ), Insert -> Module,
Copy past my code and launch it with F5.
Et voila :D
I have another one for the case when you want to delete only rows which are complete empty, but not single empty cells. It also works outside of Excel e.g. on accessing Excel by Access-VBA or VB6.
Public Sub DeleteEmptyRows(Sheet As Excel.Worksheet)
Dim Row As Range
Dim Index As Long
Dim Count As Long
If Sheet Is Nothing Then Exit Sub
' We are iterating across a collection where we delete elements on the way.
' So its safe to iterate from the end to the beginning to avoid index confusion.
For Index = Sheet.UsedRange.Rows.Count To 1 Step -1
Set Row = Sheet.UsedRange.Rows(Index)
' This construct is necessary because SpecialCells(xlCellTypeBlanks)
' always throws runtime errors if it doesn't find any empty cell.
Count = 0
On Error Resume Next
Count = Row.SpecialCells(xlCellTypeBlanks).Count
On Error GoTo 0
If Count = Row.Cells.Count Then Row.Delete xlUp
Next
End Sub
To make Alex K's answer slightly more dynamic you could use the code below:
Sub DeleteBlankRows()
Dim wks As Worksheet
Dim lngLastRow As Long, lngLastCol As Long, lngIdx As Long, _
lngColCounter As Long
Dim blnAllBlank As Boolean
Dim UserInputSheet As String
UserInputSheet = Application.InputBox("Enter the name of the sheet which you wish to remove empty rows from")
Set wks = Worksheets(UserInputSheet)
With wks
'Now that our sheet is defined, we'll find the last row and last column
lngLastRow = .Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
lngLastCol = .Cells.Find(What:="*", LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
'Since we need to delete rows, we start from the bottom and move up
For lngIdx = lngLastRow To 1 Step -1
'Start by setting a flag to immediately stop checking
'if a cell is NOT blank and initializing the column counter
blnAllBlank = True
lngColCounter = 2
'Check cells from left to right while the flag is True
'and the we are within the farthest-right column
While blnAllBlank And lngColCounter <= lngLastCol
'If the cell is NOT blank, trip the flag and exit the loop
If .Cells(lngIdx, lngColCounter) <> "" Then
blnAllBlank = False
Else
lngColCounter = lngColCounter + 1
End If
Wend
'Delete the row if the blnBlank variable is True
If blnAllBlank Then
.rows(lngIdx).delete
End If
Next lngIdx
End With
MsgBox "Blank rows have been deleted."
End Sub
This was sourced from this website and then slightly adapted to allow the user to choose which worksheet they want to empty rows removed from.
In order to have the On Error Resume function work you must declare the workbook and worksheet values as such
On Error Resume Next
ActiveWorkbook.Worksheets("Sheet Name").Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0
I had the same issue and this eliminated all the empty rows without the need to implement a For loop.
This worked great for me (you can adjust lastrow and lastcol as needed):
Sub delete_rows_blank2()
t = 1
lastrow = ActiveSheet.UsedRange.Rows.Count
lastcol = ActiveSheet.UsedRange.Columns.Count
Do Until t = lastrow
For j = 1 To lastcol
'This only checks the first column because the "Else" statement below will skip to the next row if the first column has content.
If Cells(t, j) = "" Then
j = j + 1
If j = lastcol Then
Rows(t).Delete
t = t + 1
End If
Else
'Note that doing this row skip, may prevent user from checking other columns for blanks.
t = t + 1
End If
Next
Loop
End Sub
Here is the quickest way to Delete all blank Rows ( based on one Columns )
Dim lstRow as integet, ws as worksheet
Set ws = ThisWorkbook.Sheets("NameOfSheet")
With ws
lstRow = .Cells(Rows.Count, "B").End(xlUp).Row ' Or Rows.Count "B", "C" or "A" depends
.Range("A1:E" & lstRow).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End with