Reputation: 591
I have a sheet with two columns. Column (E) contains ID and names from the data source and column (K) contains ID,which are extracted from comment section.
Column E contains sometime ID, starting with B2C, and sometime names and Id starting with 5. column K contains always ID starting with B2C. the length of the ID B2C is usually 11 to 13 Digit Long. the length of ID starting with 5 is 8 Digit Long.
I would like to have a VBA that checks both the columns, if there is an id starting with 5 or some Name in column E, then it should look into column K, if an ID starting with B2C is present, then it should copy to Column L, else copy the same value(from column E) to column L.
I researched through find and replace. I saw examples where exact Name of find was given and replaced with given Name. I am able to form an algorithm, but struck how to start with code in my case. the code below, has an runn time error
object varaible or with block variable not set .
Sub compare()
Dim i As Long
Dim ws As Worksheet
ws = Sheets("Sheet1")
For i = 1 To Rows.Count
If ws.Cells(i, 11).Value = "" Then
ws.Cells(i, 12).Value = ws.Cells(i, 5).Value
Else
ws.Cells(i, 12).Value = ws.Cells(i, 11).Value
End If
Next i
End Sub
I have an Image below, which Shows the end result.
Any lead would be appreciated.
Upvotes: 1
Views: 269
Reputation: 30047
The issue causing the error message is that you are missing a Set
statement for your worksheet object. You must use Set
when assigning an object to a variable, that is anything with its own methods. A simple data type without methods (String
, Integer
, Long
, Boolean
, ...) doesn't need the Set
statement, and can just be directly assigned like i = 0
.
Your code should be updated to:
Dim i As Long
Dim ws As Worksheet
Set ws = Sheets("Sheet1")
' RED FLAG! Rows.Count is going to cause you to loop through the entire column,
' see the below example for how to use the UsedRange property.
For i = 1 To Rows.Count
If ws.Cells(i, 11).Value = "" Then
ws.Cells(i, 12).Value = ws.Cells(i, 5).Value
Else
ws.Cells(i, 12).Value = ws.Cells(i, 11).Value
End If
Next I
An alternative which avoids even using a worksheet variable would be to use a With
block:
Dim r As Long
With ThisWorkbook.Sheets("Sheet1")
For r = 2 To .UsedRange.Rows.Count
.Range("L" & r).Value = .Range("E" & r).Value
If .Range("K" & r).Value = "" Then .Range("L" & r).Value = .Range("K" & r).Value
Next r
End With
Edit:
There are various ways to find the last used row, each with their drawbacks. A drawback of both UsedRange
and xlCellTypeLastCell
is they are only reset when you save/close/re-open the workbook. A better solution can be found in this answer.
Sub compare()
Dim r As Long, lastrow As Long, ws As WorkSheet
Set ws = ThisWorkbook.Sheets("Sheet1")
lastrow = LastRowNum(ws)
With ws
For r = 2 To lastrow
.Range("L" & r).Value = .Range("E" & r).Value
If .Range("K" & r).Value = "" Then .Range("L" & r).Value = .Range("K" & r).Value
Next r
End With
End Sub
' Function from linked question
Public Function LastRowNum(Sheet As Worksheet) As Long
LastRowNum = 1
If Application.WorksheetFunction.CountA(Sheet.Cells) <> 0 Then
LastRowNum = Sheet.Cells.Find(What:="*", LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
End If
End Function
Upvotes: 1
Reputation: 43575
This is my solution:
Option Explicit
Sub Compare()
Dim i As Long
Dim lngLastRow As Long
Dim ws As Worksheet
lngLastRow = Range("A1").SpecialCells(xlCellTypeLastCell).Row
Set ws = Worksheets(1)
With ws
.Columns(12).Clear
.Cells(1, 12) = "Extract from Comment"
For i = 1 To lngLastRow
If .Cells(i, 11).Value = "" Then
.Cells(i, 12).Value = ws.Cells(i, 5).Value
Else
.Cells(i, 12).Value = ws.Cells(i, 11).Value
End If
Next i
End With
End Sub
It clears column(12) and writes Extract from comment in the first cell of the row, to make sure that everything is clean.
lngLastRow
is the last row of the sheet.
Upvotes: 1