VBA: How to return a cell reference from a variable that looks up a value? - vba

Good day
I have a table with data, one of the columns have a number (There are repeating numbers) and the other column has letters and the last column has the feedback.
My entries change every day and I want to have one space where I can put today's Number, letter and feedback and then create a button that looks for the letter and number in the table and posts the feedback
Data Table:
Number Letter Feedback Todays Number Todays letter Todays Feedback
1 A 3 B 100
1 B
2 A
2 B
3 A
3 B
4 A
4 B
5 A
5 B
There is a similar problem posted on stack overflow and I tried to use a similar method, but this only works for searching against one criteria:
I have the following:
Private Sub CommandButton1_Click()
Dim MatchFormula As Long
MatchFormula = WorksheetFunction.Match(Range("Number"), Range("A:A"), 0)
Range("c" & MatchFormula).Value = Range("f2").Value
End Sub
Please assist

You can use AutoFilter with 2 criterias to achieve this.
Code
Option Explicit
Sub AutoFilt()
Dim Sht As Worksheet
Dim Rng As Range, VisRng As Range, FiltRngArea As Range
Dim LastRow As Long
Set Sht = ThisWorkbook.Sheets("Sheet1") ' modife "Sheet1" to your sheet's name
With Sht
.Range("A1:C1").AutoFilter
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' get last row with data in column "A"
With .Range("A1:C" & LastRow)
.AutoFilter field:=1, Criteria1:=.Range("E2").Value2
.AutoFilter field:=2, Criteria1:=.Range("F2").Value2
' set the visible rows range after Auto-Filter was applied
Set VisRng = .SpecialCells(xlCellTypeVisible)
' loop through areas of Filterred Range
For Each FiltRngArea In VisRng.Areas
If FiltRngArea.Row > 1 Then ' not header row
FiltRngArea.Cells(1, 3).Value = .Range("G2").Value ' set the value
End If
Next FiltRngArea
End With
End With
End Sub

Another approach:
Option Explicit
Private Sub CommandButton1_Click()
Dim rngNumbers As Range
Dim varCounter As Variant
Dim intTodaysNumber As Integer
Dim strTodaysLetter As String
'Determine numbers range and filter arguments
With ThisWorkbook.Worksheets("Tabelle1")
Set rngNumbers = .Range("A2", .Cells(Rows.Count, 1).End(xlUp))
intTodaysNumber = .Range("F2").Value
strTodaysLetter = .Range("G2").Value
'Loop through numbers range and compare number and letter
For Each varCounter In rngNumbers
If varCounter.Value = intTodaysNumber And _
varCounter.Offset(0, 1).Value = strTodaysLetter Then
'Write found feedback value
.Range("H2") = varCounter.Offset(0, 2).Value
debug.print "Entry found for number " & intTodaysNumber & _
" and letter " & strTodaysLetter & _
" at row " & varCounter.Row & " and column " & _
varCounter.Column
Exit For
End If
Next varCounter
End With
End Sub

Thank you for all the comments and answers. Helped a lot
Here is what worked in the end:
Private Sub CommandButton2_Click()
Dim MatchNumber As Long 'The First Row number with the matching Number'
Dim LastRow As Long 'The Last Row number with matching Number'
Dim MatchLetter As Long 'The First Row Number with Matching number and matching letter'
Dim Post As Long 'The Row Number where the feedback need sto be posted'
'Find the Row in Column A:A the matches the value in the Number range
MatchNumber = WorksheetFunction.Match(Range("Number"), Range("a:a"), 0)
'Find the Last row that mathces the number (+1 because there is only 2 entries for each number, if there was 4 entries per number then +3)
LastRow = MatchNumber + 1
'Find the Matching Letter in the new range
MatchLetter = WorksheetFunction.Match(Range("Letter"), Range(Cells(MatchNumber, 2), Cells(LastRow, 2)), 0)
'The Row number where the feedback need sto be posted
Post = MatchLetter + MatchNumber - 1
'Post the value captured in h2 to column c in the 'post' row
Range("c" & Post).Value = Range("h2").Value
End Sub

Related

VBA code to add days from one column to another

I'm having the following columns in Excel: Document Date (all cells have values) & Initial Disposition Date (there're blanks within the column).
Each Document Date cell corresponds to an Initial Disposition Date cell.
For any blank Initial Disposition Date cells, I'd like to set them to be 7 days from the corresponding Document Date. (Strictly blank cells)
Ex: Document Date = 10/01/2018. Desired Initial Disposition Date = 10/08/2018.
Is there a code to execute such action? (I have approximately 55,000 rows and 51 columns by the way).
Thank you very much! Any suggestions or ideas are highly appreciated!
Looping through a range is a little quicker in this case. I am assuming your data is on Sheet1, your Document Date is on Column A and your Initial Deposition is on Column B.
Last, you need to determine if you want that 7 days to be inclusive of weekends or not. I left you a solution for both. You will need to remove one of the action statements (in middle of loop)
Option Explicit
Sub BetterCallSaul()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LRow As Long, iRange As Range, iCell As Range
LRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Set iRange = ws.Range("B2:B" & LRow)
Application.ScreenUpdating = False
For Each iCell In iRange
If iCell = "" Then
iCell = iCell.Offset(, -1) + 7 'Includes Weekends
iCell = WorksheetFunction.WorkDay(iCell.Offset(, -1), 7) 'Excludes Weekends
End If
Next iCell
Application.ScreenUpdating = True
End Sub
If your Document Date is on Column A and you Initial Disposition Date in Column B, then the following would achieve your desired results:
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set the worksheet you are working with, amend as required
Lastrow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A
For i = 2 To Lastrow
'loop from row 2 to the last row with data
If ws.Cells(i, "B").Value = "" Then
'if there is no value in Column B then
ws.Cells(i, "B").Value = ws.Cells(i, "A").Value + 7
'add seven days to the date from Column A
End If
Next i
End Sub
A formula on all blanks would avoid the delays looping through the worksheet column(s).
Sub ddPlus7()
Dim dd As Long, didd As Long
With Worksheets("sheet1")
'no error control on the next two lines so those header labels better be there
dd = Application.Match("Document Date", .Rows(1), 0)
didd = Application.Match("Desired Initial Disposition Date", .Rows(1), 0)
On Error Resume Next
With Intersect(.Columns(dd).SpecialCells(xlCellTypeConstants, xlNumbers).EntireRow, _
.Columns(didd).SpecialCells(xlCellTypeBlanks).EntireRow, _
.Columns(didd))
.FormulaR1C1 = "=rc[" & dd - didd & "]+7"
End With
On Error GoTo 0
End With
End Sub

Count the number of records in an excel until Total is displayed

An excel file is extracted daily, and the number of records vary. Suppose 10 records are displayed, Total is displayed in the last row of A1 column. After that there is one more table below it. I need to count the number of rows from A2 to before total. Have written the below code:
myRange = Range("B65536")
If Application.WorksheetFunction.CountA(myRange) <> 0 Then
lastCol = Cells.Find("Total", Range("B1"), xlPart, , xlByRows, xlDown, False).Row
MsgBox lastCol
Else
lastCol = 1
End If
If you are looking for the word "Total" on column A, the following code will show a msgbox with the row number:
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
Dim TotalRow As Long
TotalRow = ws.Range("A:A").Find("Total").Row
'look for the word "Total" on Column A
MsgBox "Your desired Range is from A2 to A" & TotalRow
End Sub
Something as small as this one should find the row of the "Total" in the first column:
Public Sub TestMe()
Dim rowWithTotal As Long
rowWithTotal = Worksheets(1).Columns(1).Find("Total").Row
MsgBox "Row with total is - " & rowWithTotal
End Sub

VBA Excel Delete Row Based on Value in Column

Would like to delete rows from a report based on the data in column M. Report is of variable size row-wise but the same width in columns. "Valid" in a cell means it gets deleted.
Sub Create()
Dim Range1 As Range
Set Range1 = Range("M:M")
For Each cell In Range1
If ActiveCell.Value = "Valid" _
Then ActiveCell.EntireRow.Delete
Next cell
End Sub
It now about the ActiveCell but cells in the column "M:M". Also, you need to start form the bottom up (not obvious but true). So, assuming there are fewer rows than 10000, you need something like this:
Sub Create()
Dim LastRow As Long
Dim i As Long
LastRow = Range("M10000").End(xlUp).Row
For i = LastRow To 1 Step -1
If Range("M" & i) = "Valid" Then
Range("M" & i).EntireRow.Delete
End If
Next
End Sub
I found a way using your For Each :
Public Sub Create()
Dim Range1 As Range
Dim Cell
Dim LastRow As Long
Set Range1 = Range("M1")
' assume, there is some data in the first row of your sheet
LastRow = Range1.CurrentRegion.Rows.Count
' otherwise, find last cell in column M with a value, assume before row 10000
LastRow = Range("M10000").End(xlUp).Row
' select the cells to process
Set Range1 = Range(Range1, Range1.Offset(LastRow, 0))
' process the rows
For Each Cell In Range1
If Cell.Value = "Valid" Then
Debug.Print "' delete row from at address :: " & Cell.Address
Range(Cell.Address).EntireRow.Delete
End If
Next
End Sub

Looping and finding similar number in VBA

I am very new to VBA. Just started reading it up 2 days ago. I am wondering how could I write a VB codes assigned to a button to read through the whole column and search for similar numbers.
After that identifying similar numbers, it would need to move on to another column to check if the character in the column are same too.
If both of the logic = true . How can i change the cell of the value of another column?
Sample data
For the current example. The code should know that the first column had matching numbers. After that it will check for the name which is "a" in the example. After that it will automatically change the point to 1 and 0. If there are 3 same ones it will be 1,0,0 for the point
You may try recording whatever you want to do with record macros first, then filter out the codes that are not necessary. If you do not know how to record it using macros, click on the link below. You can learn from the recorded macros and slowly improvise your codes in the future from the experience you may gain.
Here's [a link] (http://www.dummies.com/software/microsoft-office/excel/how-to-record-a-macro-in-excel-2016/)
As per image attached in image I am assuming numbers are in Column A, column to check characters is Column J and result needs to be displayed in Column O then try following code.
Sub Demo()
Dim dict1 As Object
Dim ws As Worksheet
Dim cel As Range, fCell As Range
Dim lastRow As Long, temp As Long
Dim c1
Set dict1 = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Sheets("Sheet2") 'change Sheet2 to your data sheet
With ws
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row with data in Column A
c1 = .Range("A2:A" & lastRow)
For i = UBound(c1, 1) To 1 Step -1 'enter unique values with corresponding values in dict1
dict1(c1(i, 1)) = .Range("J" & i + 1) '+1 for Row 2
Next i
Set fCell = .Range("A2")
For Each cel In .Range("A2:A" & lastRow) 'loop through each cell in Column A
temp = WorksheetFunction.CountIf(.Range(fCell, cel.Address), cel) 'get count
If temp > 1 Then
If cel.Offset(0, 9) = dict1(cel.Value) Then
cel.Offset(0, 14).Value = 0
Else
cel.Offset(0, 14).Value = 1
End If
Else
cel.Offset(0, 14).Value = 1
End If
Next cel
End With
End Sub
EDIT
Sub Demo()
Dim ws As Worksheet
Dim lastRow As Long
Application.ScreenUpdating = False
Set ws = ThisWorkbook.Sheets("Sheet2") 'change Sheet3 to your data range
With ws
lastRow = .Cells(.Rows.count, "A").End(xlUp).Row 'last row with data in Column A
.Range("O2").Formula = "=IF(MOD(SUMPRODUCT(($A$2:$A2=A2)*($J$2:$J2=J2)),3)=1,1,0)" 'enter formula in Cell O2
.Range("O2").AutoFill Destination:=.Range("O2:O" & lastRow) 'drag formula down
.Range("O2:O" & lastRow).Value = .Range("O2:O" & lastRow).Value 'keep only values
End With
Application.ScreenUpdating = True
End Sub

Remove all rows that contain value VBA

I've been working on this for longer than I'd like to admit. I'm comparing two Worksheets (A & B). I'm looping through A-Column("B") and for each value in that column I'm checking it against B-Column("C"). If there's a match, I want to delete the entire row.
I've done it a number of different ways and I just can't get it to work. This is the original:
Option Explicit
Sub Purge()
Dim wipWS As Worksheet
Dim invWS As Worksheet
Dim C As Range
Dim SourceLastRow As Long
Dim DestLastRow As Long
Dim LRow As Long
Dim D As Range
Set wipWS = Worksheets("Work in Process")
Set invWS = Worksheets("Inventory Allocation")
With wipWS
' find last row in Work in Process Column B
SourceLastRow = .Cells(.Rows.count, "E").End(xlUp).Row
' find last row in Inventory Allocation Column C
DestLastRow = invWS.Cells(invWS.Rows.count, "B").End(xlUp).Row
' define the searched range in "Inventory Allocation" sheet
Set C = invWS.Range("B1:B" & DestLastRow)
Set D = wipWS.Range("E1:E" & SourceLastRow)
' allways loop backwards when deleting rows or columns
' choose 1 of the 2 For loops below, according to where you want to delete
' the matching records
' --- according to PO request delete the row in Column B Sheet A
' and the row in Column C in "Inventory Allocation" worksheet
' I am looping until row 3 looking at the PO original code
For LRow = SourceLastRow To 1 Step -1
' found a match between Column B and Column C
If Not IsError(Application.Match(.Cells(LRow, "E"), C, 0)) Then
.Cells(LRow, 2).EntireRow.Delete Shift:=xlUp
invWS.Cells(Application.Match(.Cells(LRow, "E"), C, 0), 2).EntireRow.Delete Shift:=xlUp
End If
Next LRow
End With
End Sub
It works, except it leaves 1 row left (that should be deleted). I think I know why it's happening, except I have no idea of how to do it. I've tried a For loop and it works, except I have to set a range (eg., "A1:A200") and I want it to only loop through based on the number of rows.
Any help would be greatly appreciated!
Instead of running 2 loops, you can run 1 For loop in yout Worksheets("Work in Process"), scanning Column B, and then just use the Match function to search for that value in the entire C range - which is Set to Worksheets("Inventory Allocation") at Column C (untill last row that has data).
Note: when deleting rows, allways use a backward loop (For loop counting backwards).
Code
Option Explicit
Sub Purge()
Dim wipWS As Worksheet
Dim invWS As Worksheet
Dim C As Range
Dim SourceLastRow As Long
Dim DestLastRow As Long
Dim LRow As Long
Set wipWS = Worksheets("Work in Process")
Set invWS = Worksheets("Inventory Allocation")
With wipWS
' find last row in Sheet A Column B
SourceLastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
' find last row in Sheet B Column C
DestLastRow = invWS.Cells(invWS.Rows.Count, "C").End(xlUp).Row
' define the searched range in "Inventory Allocation" sheet
Set C = invWS.Range("C1:C" & DestLastRow)
' allways loop backwards when deleting rows or columns
' choose 1 of the 2 For loops below, according to where you want to delete
' the matching records
' --- according to PO request delete the row in Column B Sheet A
' and the row in Column C in "Inventory Allocation" worksheet
' I am looping until row 3 looking at the PO original code
For LRow = SourceLastRow To 3 Step -1
' found a match between Column B and Column C
If Not IsError(Application.Match(.Cells(LRow, "B"), C, 0)) Then
.Cells(LRow, 2).EntireRow.Delete Shift:=xlUp
invWS.Cells(Application.Match(.Cells(LRow, "B"), C, 0), 3).EntireRow.Delete Shift:=xlUp
End If
Next LRow
End With
End Sub
You are comparing two Worksheets (A & B). You want to loop through A-Column("B") and for each value in that column, check against B-Column("C").
So you can have a counter (ie. bRow) to keep track of which row you are looking at in worksheet B
Dim cell as Range
Dim bRow as Integer
bRow = 1
With Worksheets("A")
For Each cell in Range(.Range("B1"), .Range("B1").End(xlDown))
If (cell.Value = Worksheets("B").Range("C" & bRow).Value0 Then
cell.EntireRow.Delete Shift:=xlUp
Worksheets("B").Range("C" & bRow).EntireRow.Delete Shift:=xlUp
Else
bRow = bRow + 1
End If
Next cell
End WIth
So I finally figured this out. It's not pretty and I'm sure there is a more elegant way of doing this, but here it is.
Option Explicit
Public Sub purWIP()
Dim wipWS As Worksheet
Dim invWS As Worksheet
Dim P As Range
Dim i As Integer, x As Integer
Set wipWS = Worksheets("Work in Process")
Set invWS = Worksheets("Inventory Allocation")
' Start by checking conditions of a certain row
For x = wipWS.UsedRange.Rows.count To 1 Step -1
With wipWS
' For each cell in wipWS I'm going to check whether a certain condition exists
For Each P In wipWS.Range(.Cells(6, 5), .Cells(wipWS.Rows.count, 5).End(xlUp))
'If it does, then I'm going to check the Inventory Allocation Worksheet to see if there's a match
If (IsDate(P.Offset(0, 7))) Then
invWS.Activate
' I do a for loop here and add 1 to i (this was the part that fixed it)
For i = invWS.UsedRange.Rows.count + 1 To 3 Step -1
If invWS.Cells(i, "B") = P.Offset(0, 0) Then
invWS.Rows(i).EntireRow.Delete Shift:=xlUp
End If
Next
P.EntireRow.Delete Shift:=xlUp
End If
Next
End With
Next
wipWS.Activate
End Sub