VBA EntireRow.Delete until specific Column - excel

I am using EntireRow.Delete to Delete some rows in my Excel Programm. It works very well!
I need a way to delete the EntireRow but I have to exclude some Columns at the end of that row.
Is it possible to call EntireRow.Delete and exclude some Columns? Here is my Code:
Dim j As Long
Dim count As Long
count = 0
Dim searchRng As Range: Set searchRng = Range("Q9:Q5000")
Dim Cell As Range
For j = searchRng.count To 1 Step -1
If ((searchRng(j).Value < CDate(TextBoxDelete.Value)) And (searchRng(j).Value <> "")) Then
count = count + 1
Debug.Print ("Cell " & count & ": " & searchRng(j).Value & " txtbox: " & TextBoxDelete.Value)
' searchRng(j).EntireRow(, -6).Delete
searchRng(j).EntireRow.Delete ' Original - works but I need to "cut off" the last columns
' searchRng(j).EntireRow.Cells(, 19).Delete
' Debug.Print searchRng.EntireRow.Offset(, 7)
End If
Next j
I have tried to use some Offset and other Functions on that line but with no luck. Does anyone know how I could change it so it deletes the entire Row but keeps the columns at the back lets say from Column "T" in place and does not delete those.

The problem is that EntireRow as the word says is the entire row. But you can use Resize to cut it off at a specific column.
Try the following
Option Explicit
Public Sub test()
Dim ws As Worksheet
Set ws = ActiveSheet ' better define your sheet like ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long ' get last used row in column Q so you only loop through actual data
LastRow = ws.Cells(ws.Rows.Count, "Q").End(xlUp).Row
Dim searchRng As Range
Set searchRng = ws.Range("Q9", "Q" & LastRow)
Dim Count As Long
Dim j As Long
For j = searchRng.Count To 1 Step -1
If (searchRng(j).Value < CDate(TextBoxDelete.Value)) And (searchRng(j).Value <> "") Then
Count = Count + 1
' clear content from column A to Q
searchRng(j).EntireRow.Resize(ColumnSize:=19).ClearContents
' check if entire row is empty
If searchRng(j).Offset(ColumnOffset:=ws.Columns.Count - searchRng(j).Column).End(xlToLeft).Column = 1 Then
' row is empty delete it
searchRng(j).EntireRow.Delete xlShiftUp
End If
End If
Next j
End Sub
This
searchRng(j).Offset(ColumnOffset:=ws.Columns.Count - searchRng(j).Column)
jumps to the very last cell in that row and then uses .End(xlToLeft) to go left until it finds a cell with data. So if the column number is 1 that means the entire row is empty and can be deleted.
So in the example below the red cells trigger the deletion
and it ends up with
As you can see the row with 1 was cleared until column T because there is more data behind, but the row with 3 was entirely deleted because it was totally empty after clearing it from A to S.
\ Edit according comment
If you don't want empty cells use
If (searchRng(j).Value < CDate(TextBoxDelete.Value)) And (searchRng(j).Value <> "") Then
Count = Count + 1
' clear content from column A to Q
searchRng(j).EntireRow.Resize(ColumnSize:=19).Delete xlShiftUp
End If

Related

How to delete these empty rows

I want to delete empty rows, such as 3-10 and 16-19. I tried the following code but it is also deleting rows 1, 2 and 15.
Dim s1 as worksheet
Dim LastRow As Long
Set s1 = ThisWorkbook.Worksheets(9)
LastRow = s1.Range("D" & s1.Rows.Count).End(xlUp).Row
With s1.Range("D2:D" & LastRow)
If WorksheetFunction.CountBlank(.Cells) > 0 Then
.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End If
End With
Looking at #cybernetic.nomads comment, and the fact that I just had a quick go, there will be a better way to do this.
If you want to delete all the empty rows, you'll (probably) need a loop.
When you delete a row your code needs to take in to account that the row numbers change (delete row 1, and now row 2 is actually row 1). You can do this by looping backward, or by re-trying the current row until all empty rows are gone then increase the row number (like my example)
Sub main()
Dim Sheet As Worksheet: Set Sheet = ThisWorkbook.Worksheets("Sheet1")
Dim Row As Integer: Row = 2 ' start row
Do
If Row > Sheet.Range("D" & Sheet.Rows.Count).End(xlUp).Row Then ' break out once you've gotten to the end
Exit Do
End If
If Application.WorksheetFunction.CountA(Sheet.Rows(Row)) = 0 Then ' check if the row is empty
Sheet.Rows(Row).Delete xlShiftUp ' delete the row and shift up
Else
Row = Row + 1 ' row was not empty, move on to the next row
End If
Loop
End Sub
your code check only column D and deletes blanks there.
text in lines 1, 2 and 15 are in columns A and B.
perhaps you could use this twist in your code?
while removed, instead i is used to check single rows
Rows are checked from bottom up
if a row has 4 blanks in columns A:D, this row is deleted
Code
Dim s1 As Worksheet
Dim LastRow As Long
Dim i As Long
Set s1 = ThisWorkbook.Worksheets(9)
LastRow = s1.Range("D" & s1.Rows.Count).End(xlUp).Row
If WorksheetFunction.CountBlank(s1.Range("A2:D" & LastRow).Cells) > 0 Then
For i = 1 To LastRow - 2: '-2 means: row 2 will be checked last. Use '-1' to check row 1 as well
If WorksheetFunction.CountBlank(Range(Cells(LastRow - i, 1), Cells(LastRow - i, 4))) = 4 Then
Rows(LastRow - i).Delete
End If
Next i
End If
Note: if you are not dealing with many rows, you might consider using integer Instead of Long
A simple solution is to check last column to garantee entire empty row
lastline = s1.Cells(Rows.Count, 4).End(xlUp).Row
i = lastline
While (i > 0)
If (s1.Cells(i, Columns.Count).End(xlToLeft).Column = 1 And s1.Cells(i, 1).Value = "") Then
s1.Rows(i).EntireRow.Delete
End If
i = i - 1
Wend
Note that the loop is backwards because (i) delete a row reindex all of the others next and (ii) classical for condition (for i = 1 to lastline) is checked just once.

Split rows based on number of linebreaks in cell VBA

I have a financial data with serial numbers linked to asset. The serial numbers are listed in cell through line breaks, i.e. there could 3,4,5 etc. serial no in a cell. So, the idea is copy and insert rows based on how many serial numbers are linked to asset in selected range. i.e. if there 4 serial no, then row should be split into 4 rows. The issue my code is that once I'm selected the range to be split, no matter that 3 or more serial numbers exist in first row it's slit into two rows, but the rest cells in range are split correctly. Not sure why the cycle within first cell in a range ends wrong.
Public Sub separate_line_range()
Dim target_col As Range
myTitle = "Select cells to be split"
Set target_col = Application.Selection
Set target_col = Application.InputBox("Select a range of cells that you want to split", myTitle, target_col.Address, Type:=8)
ColLastRow = target_col
Application.ScreenUpdating = False
For Each rng In target_col
If InStr(rng.Value, vbLf) Then
rng.EntireRow.Copy
rng.EntireRow.Insert
rng.Offset(-1, 0) = Mid(rng.Value, 1, InStr(rng.Value, vbLf) - 1)
rng.Value = Mid(rng.Value, Len(rng.Offset(-1, 0).Value) + 2, Len(rng.Value))
End If
Next
ColLastRow2 = target_col
For Each Rng2 In target_col
If Len(Rng2) = 0 Then
Rng2.EntireRow.Delete
End If
Next
Application.ScreenUpdating = True
End Sub
Please find imagine below:
I don't exactly know your task, so I put something relatively close to your task.
The issue of not correctly loop through all row is because the "RNG" you selected will not be resized after each insert row.
e.g. You are selecting row A1:C20, and there are two row added. Now the #19 and #20 are now A21:C21 & A22:C22. But the RNG is still A1:C20. The final two row will not be within the loop.
To solve your issue,
Use For i = LastRow to First Row Step -1 (Next) instead of For Each (Loop)
Here is something I do similar to your task (What I believe)
Sub Insertrow()
Dim i As Integer
Dim Lastrow As Integer
Lastrow = Worksheets("FMS1").Cells(1, 12)
For i = Lastrow To 1 Step -1
If Worksheets("FMS1").Range("J" & i) <> Worksheets("FMS1").Range("J" & i + 1) Then
Worksheets("FMS1").Range("J" & i + 1).EntireRow.Insert
Else
End If
Next
End Sub
Imagine the following data
and the following code
Option Explicit
Public Sub SplitLineBreaksIntoCells()
Const MyTitle As String = "Select cells to be split" ' define it as constant
Dim TargetCol As Range
On Error Resume Next ' next line errors if user presses cancel
Set TargetCol = Application.InputBox("Select a range of cells that you want to split", MyTitle, Application.Selection.Address, Type:=8)
On Error GoTo 0
If TargetCol Is Nothing Then
' User pressed cancel
Exit Sub
End If
Dim iRow As Long
For iRow = TargetCol.Rows.Count To 1 Step -1 ' loop from bottom to top when adding rows or row counting goes wrong.
Dim Cell As Range ' get current cell
Set Cell = TargetCol(iRow)
Dim LinesInCell() As String ' split data in cell by line break int array
LinesInCell = Split(Cell.Value, vbLf)
Dim LinesCount As Long ' get amount of lines in that cell
LinesCount = UBound(LinesInCell) + 1
' insert one cell less (one cell can be re-used)
Cell.Resize(RowSize:=LinesCount - 1).EntireRow.Insert Shift:=xlShiftDown
' inert the values from the spitted array
Cell.Offset(RowOffset:=-LinesCount + 1).Resize(RowSize:=LinesCount).Value = Application.Transpose(LinesInCell)
Next iRow
End Sub
You will get this as result:

VBA Add rows based on how many times a criteria is met

I am quite new to VBA so my question may sound silly to some of you.
I have a problem with my code. I am trying to check between 2 sheets(1st: test and 2nd: test data. In the code I am using the code name of the sheets) how may times a criteria/my product is met and based on that number to add that many rows beneath the SKU/product.
What I want to do is, if for my first product/SKU I have stock in 5 different locations, I want to add 5 rows in the first sheet and to see the qty in column D and the location in column E.
TestData tab
The reason why I need to list the quantity in different cells is that the stock is in different locations, so I can not just add in to one cell.
I am also adding screen shots of how my two sheets look like.
I have not add the loop to find the location yet, but I want to understand how to add the rows first.
Sub test()
Dim myrange As Range, testrange As Range, cell As Range, result As Range
Dim i As Long, testlastrow As Long, lastrow As Long
Dim helprng As Range
lastrow = TESTTAB.Range("a" & Rows.Count).End(xlUp).row
testlastrow = TDATA.Range("a" & Rows.Count).End(xlUp).row
Set testrange = TDATA.Range("a2:c" & testlastrow)
Set myrange = TESTTAB.Range("b2:b" & lastrow)
Set result = TESTTAB.Range("d2:e" & testlastrow)
Set helprng = TESTTAB.Range("f2:f" & lastrow)
For Each cell In myrange
For i = 1 To lastrow
If cell.Cells(i, 1) = testrange.Cells(i, 1) Then
result.Cells(i, 1) = testrange.Cells(i, 2)
End If
Next i
Next cell
End Sub
Here is the raw structure you were asking for.
Sub test()
' 011
Dim Rng As Range
Dim Tmp As Variant
Dim Radd As Long ' number of rows to add
Dim R As Long ' row counter
With Tdata
' Range, Cells and Rows Count, all in the same sheet
' exclude caption row(s)
Set Rng = .Range(.Cells(2, "A"), .Cells(.Rows.Count, "A").End(xlUp))
End With
Application.ScreenUpdating = False ' speed up the process
With TestTab
' end the loop in row 2 because row 1 might contain captions
' loop bottom to top because row numbers will change
' below the current row as you insert rwos
' column 1 = "A"
For R = .Cells(.Rows.Count, 1).End(xlUp).Row To 2 Step -1
Tmp = .Cells(R, 1).Value
Radd = Application.CountIf(Rng, Tmp)
If Radd > 1 Then
.Range(.Rows(R + 1), .Rows(R + Radd)).Insert
.Cells(R + 1, 1).Value = Radd ' for testing purposes
End If
Next R
End With
Application.ScreenUpdating = True ' now you look
End Sub
As our Evil Blue Monkey has suggested, inserting blank rows and then populating them may not be the most efficient way. You can copy a row and then click Insert to insert the copied data into a new row. Get the syntax from the Macro recorder if it's of interest. It works with the Range object the same way.

VBA: How to improve code with for and if loops

Looking for the best way to write the following code. I am currently struggling to make my code as simple and neat as possible. The code effectively takes a range and returns back the range which is non-empty.
Option Explicit
Sub ReturnNonEmptyRange()
Dim testBool As Boolean
Dim i As Long
testBool = True
For i = 2 To 10000:
If Range("G" & i) = "" Then
i = i - 1
testBool = False
End If
If testBool = False Then
Exit For
End If
Next i
MsgBox ("The range is G2:K" & i)
End Sub
Below is some sample code you can try.
The function LastUsedRow is not used, but I'm providing since it can be useful. This will return the last used row in your worksheet.
Using "Range" like you did above will assume you want to use active sheet. I always like to specify a workbook and a sheet so there is no ambiguity.
Sub Test()
' Start at row 1 and and stop when first blank cell found
Dim wks As Worksheet: Set wks = ThisWorkbook.Worksheets("Sheet1")
Dim row As Long
' Option 1: using column numbers
row = 1
Dim col As Long: col = 7 ' G
Do Until wks.Cells(row + 1, col).Value = ""
row = row + 1
Loop
MsgBox ("Last used row (in column): " & row) ' assumes something in row 1
' Option 2: using column letters
row = 1
Dim colLetter As String: colLetter = "G"
Do Until wks.Range(colLetter & row + 1).Value = ""
row = row + 1
Loop
MsgBox ("Last used row (in column): " & row) ' assumes something in row 1
End Sub
Public Function LastUsedRow(wks As Worksheet) As Long
Dim rng As Range: Set rng = wks.UsedRange ' Excel will recalc used range
LastUsedRow = rng.row + rng.Rows.Count - 1
End Function
I think your method only works if your none-empty range is consecutive. Suppose G2:G10 is non-empty, G11 is empty and G12:G20 is non-empty. Your code would come to i=11 and return G2:K10 as the non-empty range.
A more reliable, and quicker way to find the last non-empty cell (before row 1000) would be this:
range("G1000").End(xlUp).row
This will give you the first non-empty row in column G above row 1000. If row 1000 is non-empty however, it would search upwards for the last non-empty row. so you might want to change it to:
Range("G" & Rows.Count).End(xlUp).Row
This will find the last non-empty row, starting from the bottom of the worksheet.
How about combining the loop's exit conditions all into the loop control header.
I also would explicitly access the range()'s value to be more clear in the code and check the string length to be zero.
Option Explicit
Sub ReturnNonEmptyRange()
Dim testBool As Boolean
Dim i As Long
testBool = True
i = 2
While (i < 10000) And (Len(Range("G" & i).Value) <> 0)
i = i + 1
Wend
MsgBox ("The range is G2:K" & i)
End Sub
In the case this was an Array, one could not use Range("G" & Rows.Count).End(xlUp).Row. I believe #Siddharth provided a good solution. The downside being it will stop at a non- empty row.
Sub ReturnNonEmptyRange()
Dim i As Long
For i = 2 To 10000:
If Len(Trim(Range("G" & i).Value)) = 0 Then Exit For
Next i
MsgBox ("The range is G2:K" & i - 1)
End Sub

Delete rows if cell contains certain text

I want to delete the entire rows for cell that contain 'Total' and 'Nett' in column C.
I have tried the macro recording using Auto Filter but it only delete rows up to a specified range (which may differ if I use other set of data).
Appreciate your help!
Here you go. Just copy and paste this sub into your file. To use it, select the SINGLE column that you want to evaluate. This will go through every cell that has been selected, and if it matches the criteria, it will delete the entire row. Let me know if you have any questions. Good luck!
Sub DeleteRows()
'Enter the text you want to use for your criteria
Const DELETE_CRITERIA = "Test"
Dim myCell As Range
Dim numRows As Long, Counter As Long, r As Long
'Make sure that we've only selected a single column
If Selection.Columns.Count > 1 Then
MsgBox ("This only works for a single row or a single column. Try again.")
Exit Sub
End If
numRows = Selection.Rows.Count - 1
ReDim arrCells(0 To 1, 0 To numRows) As Variant
'Store data in array for ease of knowing what to delete
Counter = 0
For Each myCell In Selection
arrCells(0, Counter) = myCell
arrCells(1, Counter) = myCell.Row
Counter = Counter + 1
Next myCell
'Loop backwards through array and delete row as you go
For r = numRows To 0 Step -1
If InStr(1, UCase(arrCells(0, r)), UCase(DELETE_CRITERIA)) > 0 Then
Rows(arrCells(1, r)).EntireRow.Delete
End If
Next r
End Sub
This will loop through cells in Column C and delete the entire row if the cell contains either "Total" or "Nett". Keep in mind that it is case sensitive, so the first letter of "Nett" or "Total" would need to be capitalized for this to find it. There can be other text in the cell however. Also note that the references are not fully qualified (ie Workbook().Worksheet().Range()) because you did not provide a workbook or worksheet name. Let me know if this does not work for you.
Sub Delete()
Dim i as Integer
For i = Range("c" & Rows.Count).End(xlUp).Row To 1 Step -1
If Instr(1, Cells(i, 3), "Total") <> 0 Or Instr(1, Cells(i,3),"Nett") <> 0 Then
Cells(i,3).EntireRow.Delete
End If
Next i
End Sub

Resources