Excel VBA: What am I missing in this simple OFFSET? - vba

Code finds the header row and correct column. I want to execute some code on the range starting one cell under the header row in the same column and down to the last row in the same column. I've tried to use offset to create the range but the offset fails every time. Can offset not be used this way?
Sub Del_Y_Rows()
Dim Rng, fcell, LastRow, SrchRng, sRNG, eRNG As Range
Dim Findstring As String
Findstring = "Header"
With Sheets("thisSheet")
Set SrchRng = .Range("a1:l15")
Set fcell = SrchRng.Find(What:=Findstring, _
LookAt:=xlWhole, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
MatchCase:=False)
LastRow = .Cells(Rows.Count, fcell.Column - 2).End(xlUp).Row
Debug.Print "fcell " & fcell.Address
sRNG = .Range(fcell).Offset(1, 0) 'this fails 'sRng = start of the range
Debug.Print "srng " & sRNG
eRng = .cells(LastRow, fcell.Column) 'eRng = end of the range
Rng = .Range(sRNG, eRng)
Debug.Print "rng is " & Rng.Address
End With
End Sub

fcell is a range and the RAnge() is not needed:
sRNG = fcell.Offset(1, 0)
One more thing, You will want to use a check to make sure the fcell is actually a range and not nothing.
Sub Del_Y_Rows()
Dim Rng As Range, fcell As Range, LastRow as Long , SrchRng As Range, sRNG As Range, eRNG As Range
Dim Findstring As String
Findstring = "Header"
With Sheets("thisSheet")
Set SrchRng = .Range("a1:l15")
Set fcell = SrchRng.Find(What:=Findstring, _
LookAt:=xlWhole, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
MatchCase:=False)
LastRow = .Cells(Rows.Count, fcell.Column - 2).End(xlUp).Row
If not fcell is nothing then
Debug.Print "fcell " & fcell.Address
set sRNG = fcell.Offset(1, 0) 'this fails 'sRng = start of the range
Debug.Print "srng " & sRNG
set eRng = .cells(LastRow, fcell.Column) 'eRng = end of the range
set Rng = .Range(sRNG, eRng)
Debug.Print "rng is " & Rng.Address
End If
End With
End Sub

You must use Set for objects.
Set sRNG = .Range(fcell).Offset(1, 0)

Related

Conflicting DATA - Duplicated values

I created a macro that fills the missing Data with specific Data from another sheet , the codes works perfectly in copying pasting data from excel of the client and prepare the data needed to start the work but the only problem here below
Code:
With Worksheets("Feuil2")
' reference "target" sheet (change "Target" to our actual target sheet name)
With .Range("B1:B" & .Cells(.Rows.Count, 1).End(xlUp).Row) 'reference
its column B range from row 1 down to last not empty one
If WorksheetFunction.CountBlank(.Cells) > 0 Then
' if any blank cell in referenced range. this check to avoid error thrown by subsequent
statament
.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=index(GDC!" & rng.Offset(, 1).Address(, , xlR1C1) & ",match(RC[-1],GDC!" & rng.Address(, , xlR1C1) & ",0))" 'fill blank cells with a lookup (well, sort of) formula
.Value = .Value 'get rid of formulas and leave values only
Cells.Select
End If
End With
End With
This code works perfectly in matching and filling data but when for e.g find a duplicated value it copy only the first value not the second one
See the image below to better understand the main problem :
As you can see in the image The problem that in column A i may have data repeated twice like this value P20845 which in column F it is repeated one with the name of Ghaith and the other with the name of sirine but as you can see in the column A it is just with the name also of Ghaith and there is no name of sirine
Anyidea or better solution in solving this and getting all the needed DATA? .
Best Regards
POLOS
Or use a dictionary
Option Explicit
Public Sub AddValues()
Application.ScreenUpdating = False
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet, masterDict As Object, arr() As Variant, i As Long, rng As Range
Set wb = ThisWorkbook
Set wsSource = wb.Worksheets("Feuil1")
Set wsTarget = wb.Worksheets("Feuil2")
Set masterDict = CreateObject("Scripting.Dictionary")
With wsSource
arr = Intersect(.Columns("A:B"), .UsedRange)
For i = 1 To UBound(arr, 1)
If Not masterDict.exists(arr(i, 1)) Then masterDict.Add arr(i, 1), GetAllMatches(arr(i, 1), arr(i, 2), wsSource)
Next i
End With
With wsTarget
For Each rng In Intersect(.Columns("A"), .UsedRange)
On Error Resume Next
rng.Offset(, 1) = masterDict(rng.Value)
On Error GoTo 0
Next rng
End With
Application.ScreenUpdating = True
End Sub
Public Function GetAllMatches(ByVal findString As String, ByVal dupString As String, ByVal searchRng As Worksheet) As String
Dim foundCell As Range
Dim concatenatedString As String
concatenatedString = vbNullString
With Intersect(searchRng.Columns(1), searchRng.UsedRange)
Set foundCell = .Find(findString)
If foundCell Is Nothing Then Exit Function
If Not foundCell Is Nothing Then concatenatedString = foundCell.Offset(, 1)
Dim currMatch As Long
currMatch = 0
For currMatch = 1 To WorksheetFunction.CountIf(.Cells, findString)
Set foundCell = .Find(What:=findString, After:=foundCell, _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not foundCell Is Nothing And InStr(1, dupString, concatenatedString) = 0 Then
concatenatedString = concatenatedString & "/" & foundCell.Offset(, 1)
Else
concatenatedString = foundCell.Offset(, 1)
End If
Next currMatch
End With
GetAllMatches = concatenatedString
End Function
Output in Feuil2
Maybe something like this instead?
Sub Test()
Dim i As Long, myrow As Long, lastrow As Long
Dim sht1 As Worksheet, sht2 As Worksheet
Set sht1 = ThisWorkbook.Worksheets("Sheet1")
Set sht2 = ThisWorkbook.Worksheets("Sheet2")
lastrow = 1
For i = 1 To 7
If Application.WorksheetFunction.CountIf(sht1.Range("A:A"), sht2.Range("F" & i).Value) = 0 Then
If i = 1 Then
lastrow = 1
Else
lastrow = sht1.Cells(sht1.Rows.Count, "A").End(xlUp).Row + 1
End If
sht1.Range("A" & lastrow).Value = sht2.Range("F" & i).Value
sht1.Range("B" & lastrow).Value = sht2.Range("G" & i).Value
Else
sht1.Range("B" & sht1.Columns("A:A").Find(What:=sht2.Range("F" & i).Value).Row).Value = sht1.Range("B" & sht1.Columns("A:A").Find(What:=sht2.Range("F" & i).Value).Row).Value & "/" & sht2.Range("G" & i).Value
End If
Next i
End Sub

Modify macro for column search

I have a macro that until now was used just to search one cell from column F but now I must search for all the cell in column F. If value from F is found in range N:AN, offset(f,0,1) must have the cell value (found row , column AI).
Sub find()
Dim FindString As String
Dim Rng As Range
FindString = Sheets("Sheet1").Range("f48").Value
If Trim(FindString) <> "" Then
With Sheets("Sheet1").Range("n:an")
Set Rng = .find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Sheets("Sheet1").Range("f48").Offset(0, 1).Value = Rng.Offset(0, 21).Value
Else
Sheets("Sheet1").Range("f48").Offset(0, 1).Value = "Nothing found"
End If
End With
End If
End Sub
Perhaps this, if I understand correctly (it does assume the value in F will only be found once at most).
Sub find()
Dim Rng As Range
Dim r As Range
With Sheets("Sheet1")
For Each r In .Range("F1", .Range("F" & .Rows.Count).End(xlUp))
If Trim(r) <> vbNullString Then
With .Range("n:an")
Set Rng = .find(What:=r.Value, _
LookAt:=xlWhole, _
MatchCase:=False)
If Not Rng Is Nothing Then
r.Offset(0, 1).Value = .Cells(Rng.Row, "AI").Value
'Else
' Sheets("Sheet1").Range("f48").Offset(0, 1).Value = "Nothing found"
End If
End With
End If
Next r
End With
End Sub
See if this is helpful. Its a bit of a change but I think it may be cleaner :)
Of course you need to adjust it for your offset criteria once you "find" a match in the N:NA range
Sub Dougsloop()
Dim rCell As Range
Dim rRng As Range
Dim wsO As Worksheet
Dim aRR As Variant
Set wsO = ThisWorkbook.Sheets("Sheet1")
aRR = wsO.UsedRange.Columns("N:NA")
Set rRng = ThisWorkbook.Sheets("Sheet1").Range("F1:F500")
For Each rCell In rRng.Cells
If Trim(rCell.Value) <> vbNullString Then
thisValue = rCell.Value
If IsError(Application.Match(aRR, thisValue, 0)) = True Then
'Generic Eror Handling
ElseIf IsError(Application.Match(aRR, thisValue, 0)) = False Then
'Stuff you do when you find the match
rCell.Offset(0, 1).Value = "found it"
End If
End If
Next rCell
End Sub

Delete rows with based on cell value

I'm trying to search Column A in Sheet2 for the value of A1 in Sheet1.
If it exists, I'd like to delete the whole row in Sheet2.
If it doesn't exist, I'd like the message box to open.
Here's what I have, but I'm struggling with actually deleting the row:
Sub Delete_Rows()
Dim FindString As String
Dim Rng As Range
FindString = Sheets("Sheet1").Range("A1")
If Trim(FindString) <> "" Then
With Sheets("Sheet2").Range("A:A")
Set Rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
'I can't figure out how to delete the row
Else
MsgBox "Not Found"
End If
End With
End If
End Sub
Here is an example based on THIS
You don't need to loop. You can use .Autofilter which is faster than looping.
Sub Sample()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim delRange As Range
Dim lRow As Long
Dim strSearch As String
Set ws1 = Sheet1: Set ws2 = Sheet2
strSearch = ws1.Range("A1").Value
With ws2
'~~> Remove any filters
.AutoFilterMode = False
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("A1:A" & lRow)
.AutoFilter Field:=1, Criteria1:="=" & strSearch
Set delRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
'~~> Remove any filters
.AutoFilterMode = False
End With
If delRange Is Nothing Then
MsgBox "Not Found"
Else
delRange.Delete
End If
End Sub
Here is the code to :
loop through all the values in Column A of Sheet1,
look for all matches (with FindNext method) in Column A of Sheet 2
and delete the rows that matches
Give it a try :
Sub test_user5472539()
Dim Ws1 As Worksheet, _
Ws2 As Worksheet, _
LastRow As Long, _
FindString As String, _
FirstAddress As String, _
cF As Range
Set Ws1 = ActiveWorkbook.Sheets("Sheet1")
Set Ws2 = ActiveWorkbook.Sheets("Sheet2")
LastRow = Ws1.Range("A" & Ws1.Rows.Count).End(xlUp).Row
For i = 1 To LastRow
FindString = Ws1.Range("A" & i)
If Trim(FindString) <> "" Then
Ws2.Range("A1").Activate
With Ws2.Range("A:A")
'First, define properly the Find method
Set cF = .Find(What:=FindString, _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
'If there is a result, keep looking with FindNext method
If Not cF Is Nothing Then
FirstAddress = cF.Address
Do
cF.EntireRow.Delete
Set cF = .FindNext(cF)
'Look until you find again the first result
Loop While Not cF Is Nothing And cF.Address <> FirstAddress
Else
MsgBox "Not Found"
End If
End With
Else
End If
Next i
End Sub

How to write each inputbox entry into row one down in Excel?

I wrote an Excel macro and it seems to work fine. It displays an inputbox and once I give the value in it. It saves that value into first cell of column C (C1). However the second time I run macro I want it to be written into C2 and keep all datas in different rows in column C but each time, it writes it into C1 and cause a data loss.
Sub DataInput()
Dim SearchTarget As String
Dim myRow As Long
Dim Rng As Range
Static PrevCell As Range
Dim FoundCell As Range
Dim CurCell As Range
Dim a As String
Dim Target As Range
'SearchTarget = "asdf"
SearchTarget = InputBox("Scan or type product barcode...", "New State Entry")
If PrevCell Is Nothing Then
myRow = Selection.Row
Set PrevCell = Range("C" & myRow)
End If
'Set Rng = Range("C:C,E:E") 'Columns for search defined here
Set Rng = Range("C:C,C:C") 'Columns for search defined here
With Rng
Set FoundCell = .Cells.Find(What:=SearchTarget, _
After:=PrevCell, LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=True)
End With
If FoundCell Is Nothing Then
MsgBox SearchTarget & " was not found."
Range("C1").Value = InputBox("code?")
Range("D1").Value = Now()
Else
FoundCell.Activate
' If PrevCell.Address = FoundCell.Address Then
' MsgBox "there's only one!"
' End If
ActiveCell.Offset(0, 1).Select
timestamp = Format(Now(), "dd-mmm-yy hh:mm")
ActiveCell = timestamp
ActiveCell = Now()
ActiveCell.Offset(0, 2).Select
ActiveCell = "T141000"
ActiveCell.Offset(0, 1).Select
Set PrevCell = FoundCell
End If
End Sub
The problem here lies in your if statement - you are always storing the newly entered codes in cells C1 and the date in D1. You need to dynamically work out the next available row number and use that instead. Try something like this:
Public Sub DataInput()
...
If FoundCell Is Nothing Then
MsgBox SearchTarget & " was not found."
Dim nextFreeRow As Integer
nextFreeRow = Range("C" & Rows.Count).End(xlUp).Row + 1
Range("C" & nextFreeRow).Value = InputBox("code?")
Range("D" & nextFreeRow).Value = Now()
Else
...
End If
...
End Sub

VBA Code to Search Text

I want to amend the code below
I want the findwhat to pick text from a range ("a1:20")-which contains the list of text i want to look for
If it finds the text in the description in B, i want it to return the text it found e.g jo IN range c beside its description
Thanks
Option Explicit
Sub x()
Dim FindWhat, rngCell As Range, i As Integer
FindWhat = Array("Jo", "oa", "of", "koo")
For i = 0 To 3
For Each rngCell In Range("B2", Range("B" & Rows.Count).End(xlUp))
If InStr(rngCell, FindWhat(i)) <> 0 Then
rngCell.Offset(0, 1) = rngCell
rngCell.Offset(, 1).Resize(, 2).Copy
End If
Next rngCell
Next i
End Sub
Try this:
Option Explicit
Sub x()
Dim findRng As Range, _
targetRng As Range, _
findCell As Range, _
found As Range
Dim i As Integer
Dim firstFound As String, _
columnName As String
columnName = "B"
Set findRng = Range("A1:A20")
For Each findCell In findRng
Set targetRng = Range(columnName & "2", Range(columnName & Rows.Count).End(xlUp))
With targetRng
Set found = .Find(findCell.Value, LookIn:=xlValues, lookat:=xlPart)
If Not found Is Nothing Then
firstFound = found.Address
Do
found.Offset(0, 1).Value = found.Offset(0, 1).Value & findCell.Value & ", "
Set found = .FindNext(found)
Loop While Not found Is Nothing And found.Address <> firstFound
End If
End With
Next findCell
End Sub
Note that unless what you're doing is a little more complex than this, you can achieve this result using cell formulae. Read the help on the Index, Match and VLookup functions to see how to achieve this.