For Each Loop , Excel VBA - vba

I have an excel file that is the outcome of a PDF to Excel conversion. The data in the excel file did not come clean for some of the columns.
What needs to be accomplished:
I have created a For Each loop to go over Column "B" and find the Auction Number. Once found, a second For Each loop was created to go over Column "E" and find the first occurrence of an address and cut this cell and move it to the same row of the auction number.
Problem:
The second for each loop keeps starting from the top of column "E" and not from where the for each loop row number in column "B" ended.
The Code is about 85% complete and no errors when running
Sub Macro1()
Dim rCell As Range
Dim rCell2 As Range
Dim rCell3 As Range
Dim rRng As Range
Dim rRng2 As Range
Dim rRng3 As Range
Dim i As Integer
Dim j As Integer
Dim strMyValue As String
Set rRng = Sheet2.Range("B:B")
Set rRng2 = Sheet2.Range("E:E")
Set rRng3 = Sheet2.Range("F:F")
i = 0
j = 0
For Each rCol In rRng.Columns
For Each rCell In rCol.Rows
If InStr(rCell.Value, "FEB") > 1 Then
i = rCell.Row
Debug.Print rCell.Address, rCell.Value, rCell.Row, i
For Each rCol2 In rRng2.Columns
For Each rCell2 In rCol2.Rows
If InStr(rCell2.Value, ", PA 1") > 1 Then
If InStr(Cells(rCell2.Row + 1, "E"), ", PA 1") = 0 Then
Debug.Print Cells(rCell2.Row + 1,"E").Value
Else
Cells(rCell2.Row + 1, "E").Clear
End If
rCell2.Cut Cells(rCell.Row, "D")
Exit For
End If
Next rCell2
Next rCol2
End If
Next rCell
Next rCol
End Sub
Appreciate any help. I just cant solve it ..

Can you try this? You have more loops than you need as your ranges are only single columns; also no need to iterate through all million rows, just the used bits.
Sub Macro1()
Dim rCell As Range
Dim rCell2 As Range
Dim rCell3 As Range
Dim rRng As Range
Dim rRng2 As Range
Dim rRng3 As Range
Dim rCol As Range
Dim rCol2 As Range
Dim i As Long
Dim j As Long
Dim strMyValue As String
With Sheet2
Set rRng = .Range("B1", .Range("B" & Rows.Count).End(xlUp))
Set rRng3 = .Range("F1", .Range("F" & Rows.Count).End(xlUp))
End With
For Each rCell In rRng
If InStr(rCell.Value, "FEB") > 1 Then
i = rCell.Row
Debug.Print rCell.Address, rCell.Value, rCell.Row, i
With Sheet2
Set rRng2 = .Range(.Cells(i, "E"), .Cells(.Rows.Count, "E").End(xlUp))
End With
For Each rCell2 In rRng2
If InStr(rCell2.Value, ", PA 1") > 1 Then
If InStr(rCell2.Offset(1), ", PA 1") = 0 Then
Debug.Print rCell2.Offset(1).Value
Else
rCell2.Offset(1).Clear
End If
rCell2.Cut rCell2.Offset(,-1)
Exit For
End If
Next rCell2
End If
Next rCell
End Sub

screen shot
Thanks SJR..
I attached a screen shot of the workbook. so far you have helped me in getting the loop working for each Auction Number in column "B" to go and find the address in column "E" and place it in column "D" on the same row of the auction No.
The problems that i am facing now are two.
1.having two addresses for that auction no.
2.Not having an address at all.
The solution the i have now with code will do the following:
getting only the first address and placing it correctly but leaving the other addresses. And if their is no address like for the auction number "003FEB18", the loop will pick up cell E21 "112 WASHINGTON PLACE UNIT 4A" and place it wrongfully on cell D13 for auction number "003FEB18"
For Each rCell In rRng
If InStr(rCell.Value, "FEB") > 1 Then
i = rCell.Row
'Debug.Print rCell.Address, rCell.Value, rCell.Row, i
With Sheet2
Set rRng2 = .Range(.Cells(i, "E"), .Cells(.Rows.count,
"E").End(xlUp))
End With
For Each rCell2 In rRng2
If InStr(rCell2.Value, ", PA 1") > 1 Then
rCell2.Cut Cells(rCell.Row, "D") 'rCell2.Offset(, -1)
Exit For
End If
Next rCell2
End If
Next rCell

Related

How to find value of cell above each cell

I want to screen all sheets for values that starts with "D"
In the sheets I formed blocks (1 column, 4 rows) with
- owner
- area
- parcel (that is allways starting with a "D")
- year of transaction (blocks of 1 column and 4 rows).
I want to make a summary in sheet "Test".
I'm able to find the parcel, but how can I get the info from the cell above?
Sub Zoek_kavels()
Dim ws As Worksheet
Dim rng As Range
Dim Area
Dim Kavel As String
rij = 1
For Each ws In ActiveWorkbook.Sheets
Set rng = ws.UsedRange
For Each cell In rng
If Left(cell.Value, 1) = "D" Then 'Starts with D
Sheets("Test").Cells(rij, 1) = cell.Value 'Kavel D..
Cells(cell.row - 1, cell.Column).Select
Area = ActiveCell.Value
Sheets("Test").Cells(rij, 2) = Area 'Oppervlakte
Sheets("Test").Cells(rij, 3) = ws.Name 'Werkblad naam
rij = rij + 1
End If
Next
Next
End Sub
A nice simple loop should do the trick, you may have had spaces in the worksheet, that would throw off the used range.
Here is a different approach.
Sub Get_CellAboveD()
Dim LstRw As Long, sh As Worksheet, rng As Range, c As Range, ws As Worksheet, r As Long
Set ws = Sheets("Test")
For Each sh In Sheets
If sh.Name <> ws.Name Then
With sh
LstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("A1:A" & LstRw)
If LstRw > 1 Then
For Each c In rng.Cells
If Left(c, 1) = "D" Then
r = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1
ws.Range("A" & r).Value = c
ws.Range("B" & r).Value = c.Offset(-1).Value
ws.Range("C" & r).Value = sh.Name
End If
Next c
End If
End With
End If
Next sh
End Sub
There are two important points (and two not so important) to take care of your code:
start from row 2, because you are using .row - 1. Thus, if you start at row 1, row-1 would throw an error;
try to avoid Select, ActiveCell, etc.;(How to avoid using Select in Excel VBA);
write comments in English, not in Dutch (also good idea for variable names as well, rij or kavel do not help a lot);
declare the type of your variables, e.g. dim Area as String or as Long or anything else;
Option Explicit
Sub ZoekKavels()
Dim ws As Worksheet
Dim rng As Range
Dim Kavel As String
Dim rij As Long
Dim cell As Range
rij = 2 'start from the second row to avoid errors in .Row-1
For Each ws In ActiveWorkbook.Worksheets
Set rng = ws.UsedRange
For Each cell In rng
If Left(cell, 1) = "D" Then
With Worksheets("Test")
.Cells(rij, 1) = cell
.Cells(rij, 2) = ws.Cells(cell.Row - 1, cell.Column)
.Cells(rij, 3) = ws.Name
End With
rij = rij + 1
End If
Next
Next
End Sub
Or you can use .Cells(rij, 2) = cell.Offset(-1, 0) instead of Cells(cell.Row - 1, cell.Column), as proposed in the comments by #Shai Rado.

Can't delete rows containing certain keyword within text

I have written a macro to remove rows containing certain text in it. If either of the keyword contains any text, the macro will delete the row. However, the macro doesn't work at all. Perhaps, i did something wrong in it. Hope somebody will help me rectify this. Thanks in advance.
Here is what I'm trying with:
Sub customized_row_removal()
Dim i As Long
i = 2
Do Until Cells(i, 1).Value = ""
If Cells(i, 1).Value = "mth" Or "rtd" Or "npt" Then
Cells(i, 1).Select
Selection.EntireRow.Delete
End If
i = i + 1
Loop
End Sub
The keyword within the text I was searching in to delete:
AIRLINE DRIVE OWNER mth
A rtd REPAIRS INC
AANA MICHAEL B ET AL
ABASS OLADOKUN
ABBOTT npt P
AIRLINE AANA MTH
ABASS REPAIRS NPT
Try like this.
What about Using Lcase.
Sub customized_row_removal()
Dim rngDB As Range, rngU As Range, rng As Range
Dim Ws As Worksheet
Set Ws = Sheets(1)
With Ws
Set rngDB = .Range("a2", .Range("a" & Rows.Count))
End With
For Each rng In rngDB
If InStr(LCase(rng), "mth") Or InStr(LCase(rng), "rtd") Or InStr(LCase(rng), "npt") Then
If rngU Is Nothing Then
Set rngU = rng
Else
Set rngU = Union(rngU, rng)
End If
End If
Next rng
If rngU Is Nothing Then
Else
rngU.EntireRow.Delete
End If
End Sub
VBA syntax of your Or is wrong,
If Cells(i, 1).Value = "mth" Or "rtd" Or "npt" Then
Should be:
If Cells(i, 1).Value = "mth" Or Cells(i, 1).Value = "rtd" Or Cells(i, 1).Value = "npt" Then
However, you need to use a string function, like Instr or Like to see if a certain string is found within a longer string.
Code
Option Explicit
Sub customized_row_removal()
Dim WordsArr As Variant
Dim WordsEl As Variant
Dim i As Long, LastRow As Long
Dim Sht As Worksheet
WordsArr = Array("mth", "rtd", "npt")
Set Sht = Worksheets("Sheet1")
With Sht
' get last row in column "A"
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = LastRow To 2 Step -1
For Each WordsEl In WordsArr
If LCase(.Cells(i, 1).Value) Like "*" & WordsEl & "*" Then
.Rows(i).Delete
End If
Next WordsEl
Next i
End With
End Sub
I try to make my code sample as I can if you have any question please ask
Private Sub remove_word_raw()
'PURPOSE: Clear out all cells that contain a specific word/phrase
Dim Rng As Range
Dim cell As Range
Dim ContainWord As String
'What range do you want to search?
Set Rng = Range("A2:A25")
'sub for the word
shorttext1 = "mth"
shorttext2 = "rtd"
shorttext3 = "npt"
'What phrase do you want to test for?
ContainWord1 = shorttext1
ContainWord2 = shorttext2
ContainWord3 = shorttext3
'Loop through each cell in range and test cell contents
For Each cell In Rng.Cells
If cell.Value2 = ContainWord1 Then cell.EntireRow.Delete
Next
For Each cell In Rng.Cells
If cell.Value2 = ContainWord2 Then cell.EntireRow.Delete
Next
For Each cell In Rng.Cells
If cell.Value2 = ContainWord3 Then cell.EntireRow.Delete
Next cell
End Sub

A better way in VBA to remove a whole row if one cell contains one certain word?

I wrote the following code, which looks for 3 words in the column G and then in case, that one of those occurs it delete the whole row.
However, it is not so efficient(quick). I guess because of 3 If and ElseIf.
Does someone know a better way to do it?
Last = Workbooks("reportI.xlsm").Sheets("SII_I").Cells(Rows.Count, "G").End(xlUp).Row
For i = 2 To Last Step 1
If (Workbooks("reportI.xlsm").Sheets("SII_I").Cells(i, "G").Value) = "01NU SfG" Then
Workbooks("reportI.xlsm").Sheets("SII_I").Cells(i, "A").EntireRow.Delete
'
'with the word "01NU" in column G
ElseIf (Workbooks("reportI.xlsm").Sheets("SII_I").Cells(i, "G").Value) = "01NU" Then
Workbooks("reportI.xlsm").Sheets("SII_I").Cells(i, "A").EntireRow.Delete
'with the word "11G SfG" in column G
ElseIf (Workbooks("reportI.xlsm").Sheets("SII_I").Cells(i, "G").Value) = "11G SfG" Then
Cells(i, "A").EntireRow.Delete
End If
Debug.Print i
Next i
You can use just one if clause by using the OR operator.
If "A1"= "01NU OR "A1" = "SfG" OR "A1" = "11G SfG" Then
'delete row
Alternatively, you can get your macro to filter that column for the values 01NU, SfG, 11G SfG, and then delete all the filtered rows. This is definitely more faster.
Just replace range A1 by your required range.
Another solution:
Sub Demo()
Dim delItems As String
Dim rng As Range, searchRng As Range, cel As Range
Dim lastRow As Long
delItems = "01NU SfG,01NU,11G SfG" 'search items
With Workbooks("reportI.xlsm").Sheets("SII_I")
lastRow = .Cells(Rows.Count, "G").End(xlUp).Row
Set searchRng = .Range("G1:G" & lastRow)
For Each cel In searchRng
If InStr(1, delItems, cel.Value, vbTextCompare) Then
If rng Is Nothing Then
Set rng = .Rows(cel.Row)
Else
Set rng = Union(rng, .Rows(cel.Row))
End If
End If
Next cel
End With
rng.Delete
End Sub
The code would need a little alteration to fit your needs, but this answer is very robust and scalable.
For example:
Sub Sample()
Dim DeleteThese(3) As String, strg As String
Dim rng As Range
Dim Delim As String
Dim Last As Long
Dim ws As Worksheet
Set ws = Workbooks("reportI.xlsm").Sheets("SII_I")
Last = ws.Cells(Rows.Count, "G").End(xlUp).Row
Delim = "#"
DeleteThese(0) = "01NU SfG"
DeleteThese(1) = "01NU"
DeleteThese(2) = "11G SfG"
strg = Join(DeleteThese, Delim)
strg = Delim & strg
For i = 2 To Last Step 1
If InStr(1, strg, Delim & ws.Range("G" & i).Value & Delim, vbTextCompare) Then _
ws.Range("G" & i).EntireRow.Delete
Next i
End Sub

VBA - How to loop

I'm pretty new into this and I got stuck.
If I have a text string in column A (A1:A10) let's say. And I have a macro that looks for a keyword in that string, if it's found I want a word to be entered into column B (B1:B10).
For example A1-Pizza Hut - B1 Pizza, A2 Burger King - B2 Burger.
I got to the point where I can find the keyword, but when I try to do anything that would loop through the range, I always end up getting the same result in B.
Thank you for the answers. I thought I posted my code, but I guess it didn't. Anyways I figured out a way after looking online for the whole day.
Sub one()
Dim food As String, type As String
Dim rng As Range
Dim cel As Range
Set rng = Range("A:A")
For Each cel In rng
food = cel.Value
If InStr(UCase(food), UCase("pizza")) <> 0 Then
type = "Fast food"
Elseif InStr(UCase(food), UCase("burger")) <> 0 Then
type = "Fast food"
Else
type = "Not Fast food"
End If
cel.offset (0, 1).Value = type
Next cel
End Sub
Use a For Each Loop & Split:
Option Explicit
Public Sub Example()
Dim Sht As Worksheet
Dim rng As Range
Set Sht = ActiveWorkbook.Sheets("Sheet2")
For Each rng In Sht.Range("A1", Range("A11").End(xlUp))
rng.Offset(0, 1).Value = Split(rng, " ")(0)
Next
Set Sht = Nothing
Set rng = Nothing
End Sub
This should do what you want:
Sub Find_and_Copy():
Dim keywords() As Variant
keywords = Array("Pizza", "Burger", "Chicken")
Dim endRow As Integer
Dim SearchRng As Range
With Sheets("Sheet1")
endRow = .Cells(Rows.Count, "A").End(xlUp).Row
Set SearchRng = .Range("A1:A" & endRow).Cells
End With
Dim r As Range
Dim firstAddress As String
Dim i As Integer
For i = 0 To UBound(keywords):
With SearchRng
Set r = .Find(keywords(i), LookIn:=xlValues)
If Not r Is Nothing Then
firstAddress = r.Address
Do
Cells(r.Row, "B").Value = keywords(i)
Set r = .FindNext(r)
Loop While Not r Is Nothing And r.Address <> firstAddress
End If
End With
Next
End Sub
It will find all occurrences of each entry in the 'keywords' array that matches cells of column "A" - and of course, set column "B" to that keyword.
Note that say you have an entry like "ala Burger Chicken" it'll put 'Chicken' (which I added to 'keywords' just to keep in the spirit of things) in column B for that row because that's the last thing it did a search for - hence overwriting the previous 'Burger' entry that was in that cell.

Concatenate columns(user selected) and replace them with new column

I'm not an advanced VBA programmer. I'm working on an excel macro which will allow me to select a range(using input box) to clean the data(makes consistent with mySQL schema) on worksheet. I get this file from anther team and
1.) the order of columns is not fixed
2) levels of categories(there are few columns for categories like level1 level2 etc.) can be anything between 3-10.
I want to concatenate the columns for categories(in image level 1, level 2 etc.) using | as a separator and put the values in first category column(level1) while deleting remaining columns(level 2, level 3...[level 10]).
I removed some code from the end to reduce the length here but it still makes sense:
Sub cleanData()
Dim rngMyrange As Range
Dim cell As Range
On Error Resume Next
Do
'Cleans Status column
Set rngMyrange = Application.InputBox _
(Prompt:="Select Status column", Type:=8)
On Error GoTo 0
'Is a range selected? Exit sub if not selected
If rngMyrange Is Nothing Then
End
Else
Exit Do
End If
Loop
With rngMyrange 'with the range just selected
.Replace What:="Dead", Replacement:="Inactive", SearchOrder:=xlByColumns, MatchCase:=False
'I do more replace stuff here
End With
rngMyrange.Cells(1, 1) = "Status"
Do
'Concatenates Category Columns
Set rngMyrange = Application.InputBox _
(Prompt:="Select category columns", Type:=8)
On Error GoTo 0
'Is a range selected? Exit sub if not selected
If rngMyrange Is Nothing Then
End
Else
Exit Do
End If
Loop
With rngMyrange 'with the range just selected
'Need to concatenate the selected columns(row wise)
End With
rngMyrange.Cells(1, 1) = "Categories"
End Sub
Please do not suggest a UDF, I want to do this with macro. I must do this on files before importing them on SQL database, so a macro will be handy. Please ask if I failed to mention anything else.
EDIT: Image attached for illustration
UPDATE:
I now have a working code with help from vaskov17 on mrexcel but it does not delete the columns from where the levels are picked-level 2, level 3...etc. to shift next columns to left and the major challenge for me is to implement that code in my existing macro using range type instead of long type. I do not want to enter start column and finish column separately, instead I should be able to select range like in my original macro. Code for that macro is below, please help me:
Sub Main()
Dim start As Long
Dim finish As Long
Dim c As Long
Dim r As Long
Dim txt As String
start = InputBox("Enter start column:")
finish = InputBox("Enter ending column:")
For r = 2 To Cells(Rows.Count, "A").End(xlUp).Row
For c = start To finish
If Cells(r, c).Text <> "" Then
txt = txt & Cells(r, c).Text & "|"
Cells(r, c).Clear
End If
Next
If Right(txt, 1) = "|" Then
txt = Left(txt, Len(txt) - 1)
End If
Cells(r, start) = txt
txt = ""
Next
End Sub
I have removed the inputbox for selection of the category columns. Since they are always named Level x»y it makes it easier to find them automatically. That's why added a FindColumns() Sub to your code. It assigns the first fCol and last lCol Category column to global variables.
The ConcatenateColumns() concatenates cells in each row using "|" as separator.
The DeleteColumns() deletes the other columns
Cells(1, fCol).Value = "Category renames Level 1 to Category and Columns.AutoFit resizes all columns widths to fit the text.
Code:
Option Explicit
Dim fCol As Long, lCol As Long
Sub cleanData()
Dim rngMyrange As Range
Dim cell As Range
On Error Resume Next
Do
'Cleans Status column
Set rngMyrange = Application.InputBox _
(Prompt:="Select Status column", Type:=8)
On Error GoTo 0
'Is a range selected? Exit sub if not selected
If rngMyrange Is Nothing Then
End
Else
Exit Do
End If
Loop
With rngMyrange 'with the range just selected
.Replace What:="Dead", Replacement:="Inactive", SearchOrder:=xlByColumns, MatchCase:=False
'I do more replace stuff here
End With
rngMyrange.Cells(1, 1) = "Status"
' Concatenate Category Columns
FindColumns
ConcatenateColumns
DeleteColumns
Cells(1, fCol).Value = "Category"
Columns.AutoFit
End Sub
Private Sub FindColumns()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim i As Long, j As Long
For i = 1 To ws.Cells(1, Columns.Count).End(xlToLeft).Column
If StrComp(ws.Cells(1, i).Text, "Level 1", vbTextCompare) = 0 Then
For j = i To ws.Cells(1, Columns.Count).End(xlToLeft).Column
If InStr(1, ws.Cells(1, j).Text, "Level", vbTextCompare) Then
lCol = j
End If
Next j
fCol = i
Exit Sub
End If
Next i
End Sub
Private Sub ConcatenateColumns()
Dim rng As Range
Dim i As Long, j As Long
For i = 2 To Cells(Rows.Count, fCol).End(xlUp).Row
Set rng = Cells(i, fCol)
For j = fCol + 1 To lCol
rng = rng & "|" & Cells(i, j)
Next j
rng = "|" & rng & "|"
Set rng = Nothing
Next i
End Sub
Private Sub DeleteColumns()
Dim i As Long
For i = lCol To fCol + 1 Step -1
Columns(i).Delete Shift:=xlToLeft
Next i
End Sub