vba duplicate and partial string match - vba

I have a list of product codes where I want to mark it ** at the end of the code if there is different location.
To elaborate that, an example of the product code is PFL512241-02 where 02 is the location code. So if I get PFL512241-02 and PFL512241-03 in the list, I would like mark my result as PFL512241-02**; so smaller number of my location. If PFL512241-02 shows up 5 times, result should be PFL512241-02. If PFL512241-02 shows up one time, then I want to ignore it since I only want products that showed up more than 1 time. I am also calculating occurrence for each product.
Now my codes will only get me the product codes without ** so I need help on that part.
Option Explicit
Sub ProductNumT()
'Set up'
Dim LR1, LR2, LR3, LR4, LR5, LR6, LR7, LR8, LR9, i, j, k, l, m, n As Long
Dim Rng1, Rng2, Rng3, Rng4, cell As Range
Dim Selection, CBA, PNT As Worksheet
Set CBA = Worksheets("Master")
Set PNT = Worksheets("ProductNumT")
Set Selection = Worksheets("Selection")
LR1 = CBA.Cells(Rows.Count, "A").End(xlUp).Row
'Clear values
PNT.Columns("A:J").ClearContents
'Find products
With CBA.Range("C2", "C" & LR1)
.AutoFilter
.AutoFilter Field:=14, Criteria1:=Selection.Range("B6").Value
.Copy
PNT.Range("B2").PasteSpecial Paste:=xlPasteValues
.AutoFilter
End With
'Sort
PNT.Range("B2", "B" & LR1).Sort _
Key1:=Range("B1"), Order1:=xlAscending
'Product w/o location
LR2 = PNT.Cells(Rows.Count, "B").End(xlUp).Row
With PNT.Range("C2", "C" & LR2)
.FormulaR1C1 = "=LEFT(RC[-1],9)"
.Value = .Value
End With
For k = 2 To LR2
PNT.Cells(k, 1).Value = 1
Next k
'Find duplicates & extract unique values from the list
PNT.Range("D2", "D" & LR2).Formula = "=SUMIFS(C1,C3,RC[-1])"
PNT.Range("D2", "D" & LR2).Copy
PNT.Range("D2").PasteSpecial Paste:=xlPasteValues
For i = 2 To LR2
If PNT.Cells(i, 4).Value <= 1 Then
PNT.Rows(i).ClearContents
End If
Next i
PNT.Range("B1").ClearContents
PNT.Range("D2", "D" & LR2).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
PNT.Range("C2", "C" & LR1).Copy
PNT.Range("E2").PasteSpecial Paste:=xlPasteValues
PNT.Range("E2", "E" & LR1).RemoveDuplicates Columns:=1, Header:=xlNo
'Main calculation
LR4 = PNT.Cells(Rows.Count, "E").End(xlUp).Row
With PNT.Range("F2", "F" & LR4)
.FormulaR1C1 = "=INDEX(C2,MATCH(RC[-1],C3,0))"
.Value = .Value
End With
With PNT.Range("G2", "G" & LR4)
.FormulaR1C1 = "=INDEX(C4,MATCH(RC[-1],C2,0))"
.Value = .Value
End With
End Sub
First picture is what I have now, and second picture is my desire results.

I believe the following formula should work for column F
.FormulaR1C1 = "=INDEX(C2,MATCH(RC[-1],C3,0))&IF(COUNTIF(C2,INDEX(C2,MATCH(RC[-1],C3,0)))<COUNTIF(C3,RC[-1]),""**"","""")"
It counts how many occurrences there are of PFL180437-02 (for instance) in column B and, if that is less than the number of occurrences of PFL180437 in column C (and therefore there is some other PFL180437-xx), it appends an "**".

Not an answer, but ...
Dim LR1, LR2, LR3, LR4, LR5, LR6, LR7, LR8, LR9, i, j, k, l, m, n As Long
Dim Rng1, Rng2, Rng3, Rng4, cell As Range
Dim Selection, CBA, PNT As Worksheet
Selection is a VBA object. You can't have a variable by that name.
In the first line, only n is a Long. All the others are undefined, meaning variants. In the second line, only cell is a range, all others undefined and therefore variants. In the third line, only PNT is a worksheet, all others undefined and therefore variants.

Related

macro: copy paste cell if condition met

There’s one step that’s stuck, to update the stock number (column "D") in the database_ gudang (stock in the database_ gudang is added to the amount of receipt (column "K") from form_penerimaan)
The update is based on the name of the item (nama barang), so if the name of the item (column "C") in the form_penerimaan is the same as the name of the item (column "B") in the database_ gudang, the stock in database_ gudang will be updated.
but there’s a problem, which is updated only in rows 2,9,10 (yellow cell). A row of 3,4,5 should also be updated.
Thank you very much for your help.
Regards.
Sub Module1()
s = 10
OT1 = Sheets("Database_Gudang").Cells(Rows.Count, "D").End(xlUp).Row
For j = 2 To OT1
NB1 = Sheets("Database_Gudang").Cells(j, "B").Value
Sheets("Form_Penerimaan").Activate
If Cells(s, "C").Value = NB1 And Cells(s, "C").Value <> "" Then
Sheets("Form_Penerimaan").Cells(s, "Q").Copy
Sheets("Database_Gudang").Activate
Sheets("Database_Gudang").Cells(j, "G").Select
Selection.PasteSpecial Paste:=xlPasteValues
s = s + 1
End If
Next j
End Sub
Hi and Welcome to stackoverflow :)
Avoid the use of .Select and .Activate. Directly work with variables and objects. You may want to see How to avoid using Select in Excel VBA
You are facing that issue because you are not looping through the cells of the 2nd sheet.
Is this what you are trying? (UNTESTED)
I have commented the code so you may not have a problem in understanding it. If you do then share the exact error message and we will take it from there.
Sub Sample()
Dim wsThis As Worksheet, wsThat As Worksheet
Dim i As Long, j As Long
Dim wsThisLRow As Long, wsThatLRow As Long
'~~> Set your worksheets
Set wsThis = ThisWorkbook.Sheets("Database_Gudang")
Set wsThat = ThisWorkbook.Sheets("Form_Penerimaan")
'~~> Find relevant last row in both sheets
wsThisLRow = wsThis.Range("D" & wsThis.Rows.Count).End(xlUp).Row
wsThatLRow = wsThat.Range("C" & wsThat.Rows.Count).End(xlUp).Row
With wsThis
'~~> Loop through cell in Database_Gudang
For i = 2 To wsThisLRow
'~~> Loop through cell in Form_Penerimaan
For j = 10 To wsThatLRow
'~~> Compare values and get values across if applicable
If .Range("B" & i).Value = wsThat.Range("C" & j).Value Then
.Range("G" & i).Value = wsThat.Range("Q" & j).Value
Exit For
End If
Next j
Next i
End With
End Sub

Trying to Highlight Used Range of a Column

I'm running into trouble highlighting a column's used range. The following code creates copies of two worksheets, removes some values and then is supposed to highlight certain columns.
Sub CreateAnalysisSheets()
Dim cell, HlghtRng As Range
Dim i As Integer
Dim ref, findLast, findThis As String
Dim lastRow As Long
findLast = "2016"
findThis = "2017"
Application.ScreenUpdating = False
Sheets(1).Copy After:=Sheets(2)
ActiveSheet.Name = Left(Sheets(1).Name, InStr(1, Sheets(1).Name, " ")) & "Analysis"
Sheets(2).Copy After:=Sheets(3)
ActiveSheet.Name = Left(Sheets(2).Name, InStr(1, Sheets(2).Name, " ")) & "Analysis"
Sheets("RM Analysis").Select
For Each cell In ActiveSheet.UsedRange
If cell.Value = "NULL" Then
cell.ClearContents
End If
Next cell
For Each cell In Range("1:1")
ref = cell.Value
lastRow = Range("R" & Rows.Count & "C" & cell.Column).End(xlUp).Row
Set HlghtRng = Range(Cells(1, cell.Column) & Cells(lastRow, cell.Column))
If InStr(1, ref, findLast) > 0 And InStr(1, ref, "YTD") = 0 Then
HlghtRng.Interior.ColorIndex = 8
End If
Next cell
For Each cell In Sheets(4).UsedRange
If cell.Value = "NULL" Then
cell.ClearContents
End If
Next cell
Sheets("RM Analysis").Select
Application.ScreenUpdating = True
End Sub
The problem comes at lastRow = Range("R" & Rows.Count & "C" & cell.Column).End(xlUp).Row where I get an Method 'Range' of Object '_Global' Failed. I've tried searching for ways to fix this issue, but everything I've tried (ActiveSheet.Range and Sheets("RM Analysis").Range) has yet to work.
Anyone see where I'm going wrong here?
The xlR1C1 syntax is fouling up your request for the last non-blank cell.
lastRow = Cells(Rows.Count, cell.Column).End(xlUp).Row
I would highly recommend that you avoid relying on the ActiveSheet and use explicit parent worksheet references. This can be made quite simple using With ... End With and preceding all Range and Cells with a . like .Range(...) or .Cells(...).
Once you within a With ... End With statement, all of the references need to be prefaced with a .. Additionally, the following is not a string concatenation (e.g. &) but as .Range(starting cell comma ending cell) operation.
with worksheets("RM Analysis")
...
Set HlghtRng = .Range(.Cells(1, cell.Column), .Cells(lastRow, cell.Column))
...
end with
this should do
Columns(1).Interior.ColorIndex = 3
change the number of column as to the column you wanna highlit

If column A contains x AND column B contains y THEN add value

I'm very new to macros (it's been a few days now!) but slowly working my way through. I'd like to create a macro that adds a value of 2 to a cell if column D contains the text "(2)" AND column AG contains the text "Adult".
I've created a macro that so far changes the value of the cell to 5 (instead of adding to it) if column D contains the text "(2)" - I've spent a while messing around with "And" functions but I can't seem to find a way to make it take into account the both the "(2)" text in the D column and the "Adult" text in the AG column (I can only make it search one or the other).
Here's my attempt (this doesn't include any of my failed attempts to include the "Adult" text):
Sub BUBFindGuests()
Dim SrchRng As Range
lastRow = Range("D" & Rows.Count).End(xlUp).Row
Set SrchRng = Range("D1:D" & lastRow, "AG1:AG" & lastRow)
For Each cel In SrchRng
If InStr(1, cel.Value, "(2)") > 0 Then
With cel.Offset(0, 39)
.Offset(-1, 0) = "5"
End With
End If
Next cel
End Sub
I'm basically just trying to work out how to include the "Adult" text from the AG column, and also how to make the macro add rather than change the end value. I'm also relatively certain that some parts of my code are unnecessary or clunky, but with my level of experience I'm unsure of how to correct that. Any help would be much appreciated.
Judging by your code, you want to add 2 to column C, if that's the case this should do the trick:
Sub BUBFindGuests()
lastRow = Sheets("SHEETNAME").Range("D" & Rows.Count).End(xlUp).Row
For x = 1 to lastRow
If InStr(1, Sheets("SHEETNAME").Cells(x, 4), "(2)") <> 0 _ 'Checks column D
And Instr(1, Sheets("SHEETNAME").Cells(x, 33), "Adult") <> 0 Then 'Checks column AG
Sheets("SHEETNAME").Cells(x, 3).Value = _
Sheets("SHEETNAME").Cells(x, 3).Value + 2 'Change 3 to the appropriate column
End If
Next x
End Sub
You can search for Adult just as you searched for the (2). Just use the InStr-function two times and combine the result-booleans. You can do that in two ways, logical with And or nested with two if-statements:
If InStrResult1 **And** InStrResult2 Then 'do stuff End If
If InStrResult1 Then If InStrResult2 Then 'do stuff End If End If
Sorry for the bad formation.
You can then store the current value of your cell in a variable. Then add 2 to that variable (myVariable = myVariable + 2) and then set its value to your cell instead of 5.
EDIT: It turns out I misread your question. See revised code.
Sub BUBFindGuests()
Dim SrchRng As Range
lastRow = Range("D" & Rows.Count).End(xlUp).Row
Set SrchRng = Range("D1:D" & lastRow, "AG1:AG" & lastRow)
For Each cel In SrchRng
If InStr(1, cel.Value, "(2)") > 0 And InStr(1, cel.Value, "Adult") > 0 Then cel.Offset(-1, 39).Value = .Offset(-1, 0).Value & "5"
Next cel
End Sub

VBA Look through List

I've got the following code which gets the word dividend from a column and then takes the whole row and copy pastes it to a new sheet.
Sub SortActions()
Dim i&, k&, s$, v, r As Range, ws As Worksheet
Set r = [index(a:a,match("###start",a:a,),):index(a:a,match("###end",a:a,),)].Offset(, 6)
k = r.Row - 1
v = r
For i = 1 To UBound(v)
If LCase$(v(i, 1)) = "dividend" Then
s = s & ", " & i + k & ":" & i + k
End If
Next
s = Mid$(s, 3)
If Len(s) Then
Set ws = ActiveSheet
With Sheets.Add(, ws)
ws.Range(s).Copy .[a1]
Rows("1:1").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Sheets("20140701_corporate_action_servi").Select
Rows("2:2").Select
Selection.Copy2
Range("C32").Select
Sheets("Sheet11").Select
ActiveSheet.Paste
End With
End If
End Sub
Is there a way to make this dynamic. So if I want to search for more than word. For example if I have several rows with dividends and special dividends -> it would take all rows of dividends and all rows of special dividends and put them in separate sheets. I have tried ti with recording a macro it doesn't work as the words can differ. Maybe getting the content into a list would work. Please assist . Thanks
As suggested by #Macro Man , I am submitting images of an example sheet and sheet after filter with a simple macro for filtering one field. Please all credit to #Macro Man, it is for illustration in a simple way.
Simple code as follows.
Sub Filter1Field()
With Sheet1
.AutoFilterMode = False
With .Range("A1:H13")
.AutoFilter
.AutoFilter Field:=5, Criteria1:="Dividend"
End With
End With
End Sub
*****UPDATE*******
If your other criteria such as "Sp. Dividend" is other field but on the same row as shown in the image appended and you wish to copy to other sheet you can use the code given below. Another image shows results obtained on sheet2. You can adopt the code to your requrements.
You can use this code:
Sub Test2()
Dim LastRow As Long
Sheets("Sheet2").UsedRange.Offset(0).ClearContents
With Worksheets("Sheet1")
.Range("A1:H13").AutoFilter
.Range("A1:H13").AutoFilter field:=5, Criteria1:="Dividend"
.Range("A1:H13").AutoFilter field:=6, Criteria1:="=Sp. Dividend"
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A1:A" & LastRow).SpecialCells(xlCellTypeVisible).EntireRow.Copy _
Destination:=Sheets("Sheet2").Range("A1")
End With
End Sub

Copying specific data from a column to a new sheet for reporting

I'm very new to VBA, and I'm trying to move particular items within a column to another sheet for a report.
This is my Macro:
Sub DoIHaveaPRDesignation()
Dim rng As Range
Dim i, Lastrow
Dim splitValues() As String
Lastrow = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Sheet2").Range("A1:I500").ClearContents
Sheets("Sheet2").Cells(1, 1).Value = "Pair"
Sheets("Sheet2").Cells(1, 2).Value = "Commit"
Sheets("Sheet2").Cells(1, 3).Value = "CKID"
Sheets("Sheet2").Cells(1, 4).Value = "Status"
Sheets("Sheet2").Cells(1, 5).Value = "Terminal"
Sheets("Sheet2").Cells(1, 6).Value = "Address"
Set rng = ActiveCell
Dim moveValue As String
Do While rng.Value <> Empty
If InStr(rng.Value, " pr") = 0 Then
MsgBox "Haven't found Pair "
Else
MsgBox rng.Value
End If
Set rng = rng.Offset(1)
rng.Select
Loop
MsgBox "Done!"
End Sub
This is one instance of the data (Column A, Rows 1 - 6):
pr 1 stat RCT commit stat P
sys: type 73RMD no 1 slot: 1 lt: field stat DZ7K co stat NREQ
ckid NONE lp stat RCT 11-30-13 bp/clr 601 tea 1975 W SOUTHPORT RD
type FIXED tec IPLPINPL fld side capr 1975W:279
dist tea 7250 WINSLET BLVD type FIXED addr: 7250 WINSLET BLVD
UNIT 2D serv tea 7250 WINSLET BLVD type FIXED
The code finds the occurance of "pr", but I cannot seem to fidgure out how to pick it up and move it. I need to repeat this for the 6 columns I formatted on sheet 2, but if I get help with the first I can figure out the rest.
Thanks!
This answer discusses features of your existing code that are not recommended and introduces techniques that I believe are relevant to your requirement.
Issue 1
Dim i, Lastrow
The above declares i and Lastrow as variants which can hold anything. For example, the following code is valid:
i = "A"
i = 5
Variants can be very useful but they are slower to access than properly typed variables. I recommend:
Dim i As Long, Lastrow As Long
Issue 2
Sheets("Sheet2").Range("A1:I500").ClearContents
I assume Range("A1:I500") is intended to be larger than the area that was used on a previous run of the macro.
I would write Sheets("Sheet2").Cells.ClearContents and let Excel worry about the range used last time.
Note that ClearContents, as the name implies, only clears the contents. Clear will also clear any formatting. Sheets("Sheet2").Cells.EntireRow.Delete will delete contents and formatting and restore the column widths to their default. However, ClearContents may be adequate for your needs.
Issue 3
Sheets("Sheet2").Range("A1:I500").ClearContents
Sheets("Sheet2").Cells(1, 1).Value = "Pair"
Sheets("Sheet2").Cells(1, 2).Value = "Commit"
Sheets("Sheet2").Cells(1, 3).Value = "CKID"
Sheets("Sheet2").Cells(1, 4).Value = "Status"
Sheets("Sheet2").Cells(1, 5).Value = "Terminal"
Sheets("Sheet2").Cells(1, 6).Value = "Address"
Use of the With statement generally makes your code clearer and faster:
With Sheets("Sheet2")
.Range("A1:I500").ClearContents
.Cells(1, 1).Value = "Pair"
.Cells(1, 2).Value = "Commit"
With .Cells(1, 3)
.Value = "CKID"
.Interior.Color = RGB(0, 240, 240)
End With
.Cells(1, 4).Value = "Status"
.Cells(1, 5).Value = "Terminal"
.Cells(1, 6).Value = "Address"
End With
I have coloured cell C1 to show that With statements can be nested.
Issue 4
Set rng = ActiveCell
As I understand it, the source data is in worksheet Sheet1 and starts at cell A1. The above means your code will start at whatever cell in whatever worksheet the user has positioned the cursor. If there is a fixed starting point then set that in your code. If you do want the user to be able to control the starting point consider:
If ActiveCell.Worksheet.Name <> "Sheet1" Then
Call MsgBox("Please position the cursor to the desired starting " & _
"point in worksheet ""Sheet1""", vbOKOnly)
Exit Sub
End If
Issue 5
Set rng = ActiveCell
:
Set rng = rng.Offset(1)
rng.Select
Accessing a selected cell is much slower than accessing the cell using VBA addressing. I have also seen programmers get hopeless confused about the current location of the cursor when using Offset. You have used VBA addressing to set the header row and I have used it in my sample code below.
Issue 6
Lastrow = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
Do While rng.Value <> Empty
You set Lastrow to the number of the last row with a value but your loop moves down the column until it hits an empty cell. If there are no empty rows within the body of the data, this will give the same result. However I suggest you decide which approach is appropriate.
I would avoid the use of Empty. See What is the difference between =Empty and IsEmpty() in VBA (Excel)?.
Sample code
The following code includes the parts relevant to your question. I move the contents of cells containing " pr" to column 1 of worksheet "Sheet2" which is what you seem to be asking. However, if you wanted to split cells containing " pr" and copy selected parts to Sheet2, I would have handled your requirement in a different way. I can add a further section to this answer if you clarify what you seek.
Option Explicit
Sub MovePRRows()
Dim Rng As Range
Dim RowSheet1Crnt As Long
Dim RowSheet1Last As Long
Dim RowSheet2Crnt As Long
Dim WSht2 As Worksheet
Set WSht2 = Worksheets("Sheet2")
WSht2.Cells.EntireRow.Delete
RowSheet2Crnt = 2
With Worksheets("Sheet1")
RowSheet1Last = .Cells(Rows.Count, "A").End(xlUp).Row
For RowSheet1Crnt = 1 To RowSheet1Last
Set Rng = .Cells(RowSheet1Crnt, 1)
If Rng.Value <> "" Then
If InStr(1, Rng.Value, " pr") <> 0 Then
Rng.Copy Destination:=WSht2.Cells(RowSheet2Crnt, 1)
RowSheet2Crnt = RowSheet2Crnt + 1
End If
End If
Next
End With
End Sub