I am a beginner to VBA. On sheet one I have data formatted like this:
SHEET 1
What I want to do is use VBA to spit out the following graph which dynamically populates the region depending on how many it finds:
SHEET 2
This is my first bit of VBA so I am struggling a bit. This is my idea of how to approach this problem:
My idea was to scroll down the string in my data in sheet1 col A and determine if it's a date we have seen before or not:
Public Sub Test()
ActiveSheet.Range("Sheet1!A1:A5000").AdvancedFilter Action:=xlFilterCopy, CopyToRange.Range("Sheet2!A1"), Unique:=True
End Sub
Questions
Is this flow diagram taking the right approach?
If so, how do I implement this kind of "Is this unique, if so do this, if not do this" kind of setup.
How can I start this code so I have something to build on?
This is what I have so far:
https://gist.githubusercontent.com/employ/af67485b8acddce419a2/raw/6dda3bb1841517731867baec56a0bf2ecf7733a7/gistfile1.txt
For different approach please see below:
Sheet 1 layout (Source):
Sheet 2 Layout (Target):
Sub SalesRegion()
Dim ws1, ws2 As Worksheet
Dim wb As Workbook
Dim ws1LastRow, ws2LastRow, salesVal As Long
Dim destFind, dateFind As Range
Dim destStr As String
Dim dateStr As Date
Dim targetCol, targetRow As Long
Set wb = ActiveWorkbook '<- Your workbook
Set ws1 = wb.Sheets("Sheet1") '<- Your source worksheet
Set ws2 = wb.Sheets("Sheet2") '<- Your destination worksheet
ws1LastRow = ws1.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To ws1LastRow
destStr = ws1.Range("C" & i).Value
dateStr = ws1.Range("A" & i).Value
salesVal = ws1.Range("B" & i).Value
With ws2.Rows("1:1") '<- row on destination sheet which contains countries
Set destFind = .Find(What:=destStr, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not destFind Is Nothing Then
targetCol = destFind.Column
With ws2.Columns("A:A") '<- Column on destination sheet which contains months
'You may need to adjust date format below depending on your regional settings
Set dateFind = .Find(What:=Format(ws1.Range("A" & i).Value, "MMM-yy"), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not dateFind Is Nothing Then
targetRow = dateFind.Row
ws2.Cells(targetRow, targetCol).Value = ws2.Cells(targetRow, targetCol).Value + salesVal
Else
ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = dateStr
targetRow = ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Row
ws2.Cells(targetRow, targetCol).Value = salesVal
End If
End With
Else
ws2.Cells(1, Columns.Count).End(xlToLeft).Offset(0, 1).Value = destStr
targetCol = ws2.Cells(1, Columns.Count).End(xlToLeft).Column
With ws2.Columns("A:A") '<- Column on destination sheet which contains months
'You may need to adjust date format below depending on your regional settings
Set dateFind = .Find(What:=Format(ws1.Range("A" & i).Value, "MMM-yy"), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not dateFind Is Nothing Then
targetRow = dateFind.Row
ws2.Cells(targetRow, targetCol).Value = ws2.Cells(targetRow, targetCol).Value + salesVal
Else
ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = dateStr
targetRow = ws2.Range("A" & Rows.Count).End(xlUp).Row
ws2.Cells(targetRow, targetCol).Value = salesVal
End If
End With
End If
End With
Next
End Sub
First, I agree with the others that you should look for a solution using the built-in capabilities of the Pivot Table.
Since you've mentioned that it does not meet your expectations, I threw together some code that works to summarize the data as you've requested. Let me know if it does the trick, if you need any added help adjusting it for your needs, or if you have any other general questions.
Sub SummarizeInNewSheet()
Dim wsOrigin As Worksheet
Dim wsDest As Worksheet
Dim rngOrigin As Range
Dim oDict As Object
Dim cel As Range
Dim rngLocations As Range
Dim nLastRow As Long
Dim nLastCol As Long
Dim rngInterior As Range
Dim rngAllDates As Range
Dim rngAllLocations As Range
Dim rngAllSales As Range
Application.ScreenUpdating = False
Set wsOrigin = Worksheets("Sheet1")
Set wsDest = Worksheets("Sheet2")
Set rngOrigin = wsOrigin.Range("A1").CurrentRegion
Intersect(rngOrigin, wsOrigin.Columns(1)).Copy wsDest.Range("A1")
wsDest.Range(wsDest.Range("A1"), wsDest.Range("A1").End(xlDown)).RemoveDuplicates Columns:=1, Header:=xlYes
Set oDict = CreateObject("Scripting.Dictionary")
Set rngLocations = wsDest.Range("B1")
For Each cel In Intersect(rngOrigin, wsOrigin.Columns(3))
If cel.Row = 1 Then
Else
If oDict.exists(cel.Value) Then
'Do nothing for now
Else
oDict.Add cel.Value, 0
rngLocations.Value = cel.Value
Set rngLocations = rngLocations.Offset(, 1)
End If
End If
Next cel
nLastRow = wsDest.Cells(Rows.Count, 1).End(xlUp).Row
nLastCol = wsDest.Cells(1, Columns.Count).End(xlToLeft).Column
Set rngInterior = wsDest.Range(wsDest.Range("B2"), wsDest.Cells(nLastRow, nLastCol))
Set rngAllDates = wsOrigin.Range(wsOrigin.Range("A2"), wsOrigin.Range("A2").End(xlDown))
Set rngAllSales = wsOrigin.Range(wsOrigin.Range("B2"), wsOrigin.Range("B2").End(xlDown))
Set rngAllLocations = wsOrigin.Range(wsOrigin.Range("C2"), wsOrigin.Range("C2").End(xlDown))
For Each cel In rngInterior
cel.Value = Application.WorksheetFunction.SumIfs(rngAllSales, rngAllDates, wsDest.Cells(cel.Row, 1), rngAllLocations, wsDest.Cells(1, cel.Column))
Next cel
Application.ScreenUpdating = True
End Sub
Related
I am trying to make something that would look like this:
In the table on the right there will be all the unique records which will be stored in a certain area. However some record may be existing in more areas, and this information can be taken from the list in column A and B. The macro should take each unique record in column D and search for it in Column A, every time it finds it, should copy the location/area in column B and pasted next to the unique record in the table. I think I could do this with a loop, but what I created in the code below does not really works.
The second challenge is to make it understand that in a location has been copy into the table, the new found location needs to be pasted in the next free cell of that same unique record.
I am aware my code is a little scare but I would appreciate even just advice on which direction I should be looking... Thanks in advance!
Sub searcharea()
Dim UC As Variant, UCrng As Range, ra As Range
Set UCrng = Range("F2:F6")
For Each UC In UCrng
Set ra = Cells.Find(What:=UC, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
ra.Offset(0, 1).Copy Destination:=Range("E2")
Next
End Sub
I would suggest looping through all Rows (Columns A + B), e.g.:
For i = 1 to Rows.Count
'DoStuff
Next i
For each row, you copy the value of A into D, if it is not there already.
You can access the values like this:
Cells(i, "A").Value
Cells(i, "B").Value
For finding values in a column, see here. If you found a duplicate, use another loop to check which column (E, F, G,..) in your specific row is the first empty one, and past the value of column B there.
Take a try:
Option Explicit
Sub test()
Dim LastRowA As Long, LastRowD As Long, i As Long, rngColumn As Long
Dim rng As Range
With ThisWorkbook.Worksheets("Sheet1")
LastRowD = .Cells(.Rows.Count, "D").End(xlUp).Row
.Range("D2:J" & LastRowD).ClearContents
LastRowA = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRowA
LastRowD = .Cells(.Rows.Count, "D").End(xlUp).Row
Set rng = .Range("D1:D" & LastRowD).Find(.Range("A" & i).Value, LookIn:=xlValues, lookat:=xlWhole)
If Not rng Is Nothing Then
rngColumn = .Cells(rng.Row, .Columns.Count).End(xlToLeft).Column
Cells(rng.Row, rngColumn + 1).Value = .Range("B" & i).Value
Else
.Range("D" & LastRowD + 1).Value = .Range("A" & i).Value
.Range("E" & LastRowD + 1).Value = .Range("B" & i).Value
End If
Next i
End With
End Sub
I think this code will do what you want. Please try it.
Option Explicit
Sub SortToColumns()
' Variatus #STO 30 Jan 2020
Dim WsS As Worksheet ' Source
Dim WsT As Worksheet ' Target
Dim Rng As Range
Dim Fn As String, An As String ' File name, Area name
Dim Rls As Long
Dim Rs As Long
Dim Rt As Long, Ct As Long
With ThisWorkbook ' change as required
Set WsS = .Worksheets("Sheet1") ' change as required
Set WsT = .Worksheets("Sheet2") ' change as required
End With
With WsT
' delete all but the caption row
.Range(.Cells(2, 1), .Cells(.Rows.Count, "A").End(xlUp)).EntireRow.ClearContents
End With
Application.ScreenUpdating = False
With WsS
' find last row of source data
Rls = .Cells(.Rows.Count, "A").End(xlUp).Row
For Rs = 2 To Rls ' start from row 2 (row 1 is caption)
Fn = .Cells(Rs, "A").Value
An = .Cells(Rs, "B").Value
If FileNameRow(Fn, WsT, Rt) Then
' add to existing item
With WsT
Ct = .Cells(Rt, .Columns.Count).End(xlToLeft).Column
Set Rng = .Range(.Cells(Rt, "B"), .Cells(Rt, Ct))
End With
With Rng
Set Rng = .Find(An, .Cells(.Cells.Count), xlValues, xlWhole, xlByRows, xlNext)
End With
' skip if Area exists
If Rng Is Nothing Then WsT.Cells(Rt, Ct + 1).Value = An
Else
' is new item
WsT.Cells(Rt, "A").Value = Fn
WsT.Cells(Rt, "B").Value = An
End If
Next Rs
End With
Application.ScreenUpdating = True
End Sub
Private Function FileNameRow(Fn As String, _
WsT As Worksheet, _
Rt As Long) As Boolean
' Rt is a return Long
' return True if item exists (found)
Dim Fnd As Range
Dim Rng As Range
Dim R As Long
With WsT
R = .Cells(.Rows.Count, "A").End(xlUp).Row
Set Rng = .Range(.Cells(2, "A"), .Cells(R, "A"))
Set Fnd = Rng.Find(Fn, Rng.Cells(Rng.Cells.Count), xlValues, xlWhole, xlByRows, xlNext)
If Fnd Is Nothing Then
Rt = Application.Max(.Cells(.Rows.Count, "A").End(xlUp).Row + 1, 2)
Else
Rt = Fnd.Row
FileNameRow = True
End If
End With
End Function
I'm working on a macro that needs to find every value in a range in "sheet1" and search for it in all the sheets of the workbook (may be up to 7 sheets), as it takes too long, looking for the values in the entire sheets, I would like to reduce the search field on each sheet up to one variable column with header IP.
This is the macro I have so far, but I can't get it to work only on that specified range, however, removing those lines makes the macro work ok.
Thank you in advance.
Sub findInventory()
Dim ws As Worksheet
Dim strWhat, rngFound, mString As String
Dim rngSearch, osfind, rfind, rfcol As Range
Dim i, x As Integer
Dim LastRow, oscol, lcol, e, lrowA, remChar, fcol As Long
Sheets("GVM Report").Cells(1, 1).Offset(0, 1).Resize(, 2).EntireColumn.Insert
Sheets("GVM Report").Cells(1, 1).Offset(0, 1).Value = "INVENTORY"
Sheets("GVM Report").Cells(1, 1).Offset(0, 2).Value = "OPSDB"
Set rfind = ActiveWorkbook.Sheets("GVM Report").Rows("1:3").Find(What:="IP", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
lcol = rfind.Column
Set osfind = ActiveWorkbook.Sheets("GVM Report").Rows("1:3").Find(What:="OS*", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
oscol = osfind.Column
LastRow = Sheets("GVM Report").Range("A" & Rows.Count).End(xlUp).Row
For x = 2 To LastRow
strWhat = Sheets("GVM Report").Cells(x, lcol)
For Each ws In Worksheets
Set rfcol = ws.Rows("1:3").Find(What:="IP", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
fcol = rfcol.Column
With ws.Columns(fcol)
Select Case ws.name
Case "Operations", "Data", "FYI all OS", "Unique Values", "GVM Report"
Case Else
Set rngSearch = ws.Cells.Find(What:=strWhat)
If strWhat <> "" Then
If Not rngSearch Is Nothing Then
i = i + 1
If i = 1 Then
rngFound = rngSearch.Worksheet.name
Else
rngFound = rngFound & " | " & rngSearch.Worksheet.name
End If
End If
End If
Sheets("GVM Report").Cells(x, 2) = rngFound
End Select
End With
Next ws
rngFound = ""
i = 0
Next x
End Sub
I'm not sure if I can replicate your error, but I've tidied up your code a little and it might be useful for you, so here it goes:
Sub findInventory()
Dim ws As Worksheet
Dim wsGVM As Worksheet: Set wsGVM = ThisWorkbook.Sheets("GVM Report")
Dim strWhat As String, rngFound As String, mString As String
Dim rngSearch As Range, osfind As Range, rfind As Range, rfcol As Range
Dim i As Integer, x As Long, LastRow As Long, oscol As Long, lcol As Long, fcol As Long
wsGVM.Cells(1, 1).Offset(0, 1).Resize(, 2).EntireColumn.Insert
wsGVM.Cells(1, 1).Offset(0, 1).Value = "INVENTORY"
wsGVM.Cells(1, 1).Offset(0, 2).Value = "OPSDB"
Set rfind = wsGVM.Rows("1:3").Find(What:="IP", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not rfind Is Nothing Then lcol = rfind.Column
Set osfind = wsGVM.Rows("1:3").Find(What:="OS*", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not osfind Is Nothing Then oscol = osfind.Column
LastRow = wsGVM.Range("A" & Rows.Count).End(xlUp).Row
For x = 2 To LastRow
strWhat = wsGVM.Cells(x, lcol)
For Each ws In Worksheets
Set rfcol = ws.Rows("1:3").Find(What:="IP", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not rfcol Is Nothing Then
fcol = rfcol.Column
With ws.Columns(fcol)
Select Case ws.Name
Case "Operations", "Data", "FYI all OS", "Unique Values", "GVM Report"
''''
Case Else
If strWhat <> "" Then
Set rngSearch = .Find(What:=strWhat)
If Not rngSearch Is Nothing Then
i = i + 1
If i = 1 Then
rngFound = rngSearch.Worksheet.Name
Else
rngFound = rngFound & " | " & rngSearch.Worksheet.Name
End If
End If
End If
wsGVM.Cells(x, 2) = rngFound
End Select
End With
End If
Next ws
rngFound = ""
i = 0
Next x
End Sub
I did a test with dummy'ed up data and got the following results:
INVENTORY
Sheet2 | Sheet3
Sheet2
Sheet3
which is consistent with what I would expect given the dummy data I created. Perhaps there are leading, trailing spaces or other non-visible difference that cause a data mismatch on cells that appear to be equal?
(New to scrip writing) I am working on a BOM to add cost informatioin for parts from another spreadsheet and add it to my BOM spreadsheet. The code I have works fine until the part number is not found. Then I get the Object variable ..not set.
Sub Costin()
Dim Partno
Dim LastcRow
Dim Rowno
LastcRow = Range("B" & Rows.Count).End(xlUp).Row
LastccRow = Range("A" & Rows.Count).End(xlUp).Row
Rowno = 4
Workbooks("cost_bom.txt").Activate
Worksheets("cost_bom").Select
' GET FIRST PART NUMBER
Range("b4").Select
Partno = ActiveCell.Value
' FIND COST OF ACTIVE PART
For Rowno = 4 To LastcRow
Windows("Comp-cost.xlsx").Activate
Columns("A").Select
Selection.Find(what:=Partno, After:=ActiveCell, LookIn:=xlFormulas _
, Lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
' >> Gives Object error on start if not commented out
' If Partno Is Nothing Then
' Windows("COST_BOM.txt").Activate
' ActiveCell.Offset(0, 5).Select
' ActiveCell.Value = "$$$$"
' Else
' End If
ActiveCell.Offset(0, 1).Select
Cost = ActiveCell.Value
' COPY COST TO BOM
Application.CutCopyMode = False
Selection.Copy
Windows("COST_BOM.txt").Activate
ActiveCell.Offset(0, 5).Select
Application.CutCopyMode = False
ActiveCell.Value = Cost
Cells(Rowno, 2).Select
Partno = ActiveCell.Value
Next Rowno
End Sub
I tried to change the code to not use select and activate. It runs through and fills the cells but instead of the value it returns #N/A
I want it to look at all values (part Numbers) from column B4 to end in the first workbook and find the same value in another workbook and return the adjacent cell value (Cost) to the first workbook.
This is part of a larger module which pulls the info from a CAD program and creates the BOM
I can't figure out what the search is looking at.
Dim C As Integer, n As Integer
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rngLookup As Range
Dim v
Application.ScreenUpdating = True
Set wb1 = Workbooks("cost_bom.txt")
Set ws1 = wb1.Sheets("cost_bom")
ws1.Range("g4:g100000").ClearContents
Set wb2 = Workbooks("comp-price.xlsx")
With wb2.Sheets("Sheet1")
Set rngLookup = .Range(.Cells(2, 1), .Cells(2, 2).End(xlDown)).Resize(, 3)
End With
With ws1
C = 4
Do Until .Cells(C, 2) = ""
v = Application.VLookup(.Cells(C, 2).Value, rngLookup, 2, False)
' If Not IsError(v) Then
.Cells(C, 7).Value = v
C = C + 1
Loop
End With
I'm not sure why your VLookup isn't working so i tried to replicate it with .Find. Give the below code a try and let me know if it works.
Sub MoveData()
Dim wbk1 As Workbook, wbk2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim lRow1 As Long, lRow2 As Long
Dim Cell As Range, Found As Range
Set wbk1 = Workbooks("cost_bom.txt")
Set wbk2 = Workbooks("comp-price.xlsx")
Set ws1 = wbk1.Worksheets("cost_bom")
Set ws2 = wbk2.Worksheets("Sheet1")
With ws2
'Find last row in Col B
lRow2 = .Range("B" & .Rows.Count).End(xlUp).Row
'Loop through col B to find values
For Each Cell In .Range("B4:B" & lRow2)
'Search ws1 for Value
Set Found = ws1.Columns(2).Find(What:=Cell.Value, _
After:=ws1.Cells(1, 2), _
LookIn:=xlFormulas, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
If Not Found Is Nothing Then
Cell.Offset(0, 5).Value = ws1.Cells(Found.Row, Found.Column + 1).Value
End If
Next Cell
End With
End Sub
There are two Excel workbooks, Master and Survey Responses.
I have to loop through each row in Survey Responses, to select the value from the 4th column and compare it to the 4th column in Master. If there is no match then copy the complete row from Survey Responses to the end of Master. For the first time there will be no rows in Master so all rows must be copied from Survey Responses.
Survey Responses
The below code does not loop through all rows and if I run it a second time it copies all rows without performing the comparison.
'''''Define Object for Target Workbook
Dim Target_Workbook As Workbook
Dim Source_Workbook As Workbook
Dim Source_Path As String
'''''Assign the Workbook File Name along with its Path
Source_Path = "C:\Users\Survey Responses\Survey Response.xls"
Set Source_Workbook = Workbooks.Open(Source_Path)
Set Target_Workbook = ThisWorkbook
'''''With Source_Workbook object now, it is possible to pull any data from it
'''''Read Data from Source File
'''''Logic to select unique rows only
Dim rngSource As Range, rngTarget As Range, cellSource As Range, cellTarget As Range
Set rngSource = Source_Workbook.Sheets(1).Range("Responses")
Set rngTarget = Target_Workbook.Sheets(2).Range("Responses")
Dim rowNr_target As Integer, Rng As Range
With Target_Workbook.Sheets(2)
rowNr_target = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Dim counter As Integer, found As Boolean, inner_counter As Integer
counter = 1
For Each cellSource In rngSource.Rows
'On Error Resume Next
If cellSource.Cells(counter, 1).Value = "" Then
Exit For
End If
found = False
inner_counter = 1
For Each cellTarget In rngTarget.Rows
If cellTarget.Cells(inner_counter, 1).Value = "" Then
Exit For
End If
''''test = Application.WorksheetFunction.VLookup(test1, rngTarget, 1, False)
If (cellSource.Cells(counter, 4) = cellTarget.Cells(inner_counter, 4)) Then
found = True
Exit For
End If
inner_counter = inner_counter + 1
Next
If (found = False) Then
cellSource.EntireRow.Copy
If (rowNr_target > 1) Then
rngTarget.Rows(rowNr_target + 1).Insert
Else
rngTarget.Rows(rowNr_target).Insert
End If
rowNr_target = rowNr_target + 1
End If
counter = counter + 1
'On Error GoTo 0
Next
'''''Target_Workbook.Sheets(2).Range("Responses").Value = Source_data
'''''Close Target Workbook
Source_Workbook.Save
Target_Workbook.Save
''''Source_Workbook.Close False
'''''Process Completed
MsgBox "Task Completed"
Updated code:
Dim cel As Range
Dim rng As Range
Dim r As Range
Dim lastrow As Long
Dim Target_Workbook As Workbook
Dim Source_Workbook As Workbook
Dim Source_Path As String
'''''Assign the Workbook File Name along with its Path
Source_Path = "C:\Users\Survey Responses\Survey Response.xls"
Set Source_Workbook = Workbooks.Open(Source_Path)
Set Target_Workbook = ThisWorkbook
Dim rngSource As Range, rngTarget As Range, cellSource As Range, cellTarget As Range
Set rngSource = Source_Workbook.Sheets(1).Range("Responses")
Set rngTarget = Target_Workbook.Sheets(2).Range("Responses")
With Target_Workbook.Sheets(2)
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
For Each cel In Source_Workbook.Sheets(1).Range("D:D")
If cel.Value = "" Then
Exit For
End If
Set r = .Range("D:D").Find(What:=cel, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If r Is Nothing Then
cel.EntireRow.Copy
rngTarget.Rows(lastrow).Insert
''If Not rng Is Nothing Then Set rng = Union(rng, cel) Else Set rng = cel
End If
Next cel
''rng.Copy.Range("A" & lastrow).PasteSpecial xlPasteValues
End With
'''''Close Target Workbook
Source_Workbook.Save
Target_Workbook.Save
''''Source_Workbook.Close False
'''''Process Completed
MsgBox "Task Completed"
This is untested code but it should help you with anything you already have. You will need to adjust the ranges to suit yourself, but it will loop through one sheet and collect values that dont exists and then copy them to another sheet.
Try this,
Sub dave()
Dim cel As Range
Dim rng As Range
Dim r As Range
Dim lastrow As Long
With Sheets("Master")
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
For Each cel In Sheets("Sheet1").Range("D1:D22")
Set r = .Range("D:D").Find(What:=cel, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If r Is Nothing Then
If Not rng Is Nothing Then Set rng = Union(rng, cel) Else Set rng = cel
End If
Next cel
rng.Copy
.Range("A" & lastrow).PasteSpecial xlPasteValues
End With
End Sub
I am new in VBA and I am trying to solve one problem. I have Only Items column in Excel data like below. And I want to add code for each item which is in Code column.
Code Items
Animals:
AN Cow
AN Dog
AN Zeebra
AN Deer
Flower:
FL Rose
FL Sunflower
Fruit:
FR Mango
FR Banana
FR Pineapple
FR Cherry
I used following Loop for that
For Each Cell In Sheets("Sheet1").Range("B" & Sheets("Sheet1").Columns("B:B").Cells.Find(what:="Animal:", searchdirection:=xlPrevious).Offset(1, 0).Row & ":B" & Sheets("Sheet1").Range("B").End(xlDown).Row)
If Cell.Value <> "Flower:" Then
Cell.Offset(1, 0).Select
Cell.Offset(0, -1).Value = "AN"
ElseIf Cell.Value = "Flower:" Then
Range(Selection, Selection.End(xlDown)).Select
Cell.Offset(0, -1).Value = "FL"
End If
Next Cell
But, this is not acheiving what I need. can please someone let me know what to do in this case?
This code uses a different approach (do while) but achieves what you want. It identifies the category by looking for a colon : within the cell. It then sets the code and applies it to the offset(0,-1) until a new code is found.
Sub FillOffset()
Dim ws As Worksheet
Set ws = Sheets("Sheet1")
Dim i As Long
i = 2
Dim cell As Range
Do Until i > ws.Range("B" & Rows.Count).End(xlUp).Row
If InStr(1, ws.Range("B" & i).Text, ":", vbTextCompare) Then
Dim code As String
code = UCase(Left(ws.Range("B" & i).Text, 2))
Else
ws.Range("B" & i).Offset(0, -1) = code
End If
i = i + 1
Loop
End Sub
Sample output:
#mehow beat me by a a few seconds, but this code will also solve your problem.
Sub AddCodeForItems()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Dim lastRow As Long
Dim code As String
Set ws = ThisWorkbook.ActiveSheet
lastRow = ws.Range("B" & ws.Rows.Count).End(xlUp).Row
Set rng = ws.Range("B2:B" & lastRow)
For Each cell In rng
If Right(Trim(cell.Value), 1) = ":" Then
code = UCase(Left(Trim(cell.Value), 2))
Else
cell.Offset(, -1).Value = code
End If
Next cell
End Sub
Slightly different approach:
Sub tgr()
Dim rngFound As Range
Dim rngLast As Range
Dim strFirst As String
With ActiveSheet.Columns("B")
Set rngFound = .Find(":", .Cells(.Cells.Count), xlValues, xlPart)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
Set rngLast = Range(rngFound.Offset(1), .Cells(.Cells.Count)).Find(":", , xlValues, xlPart)
If rngLast Is Nothing Then Set rngLast = .Cells(.Cells.Count).End(xlUp).Offset(1)
Range(rngFound.Offset(1, -1), rngLast.Offset(-1, -1)).Value = UCase(Left(rngFound.Text, 2))
Set rngFound = Columns("B").Find(":", rngFound, xlValues, xlPart)
Loop While rngFound.Address <> strFirst
End If
End With
Set rngFound = Nothing
Set rngLast = Nothing
End Sub