I use a third party to collect data in order to produce a monthly report. In this example, the data dump from the third party is in the sheet called "Data" and the report sheet is called "Month"
Sheets("Data") This is the data dump of unstructured data listed by segment, although the order of the segments do not match my report:
Sheets("Month") This is the structured reporting sheet that lists data by segment appropriate for the report. Copied data from the 'Data' sheet will be pasted into columns O through S
I am looking to write a loop that can search through "Data", find each successive word in column B "Month" and paste the appropriate information from "Data" into "Month".
Right now, I have a long code that works, but it is easily broken if one of the segment names change. This is a small piece that just focuses on Segment 4.
Sub Macro1()
' Macro1 Macro
' For post onto StackOverflow
Dim ws As Worksheet
Dim qb As Worksheet
Dim aCell As Range
Set ws = ThisWorkbook.Sheets("Month")
Set qb = ThisWorkbook.Sheets("Data")
'To find Segment 4
With ws
Set aCell = .Columns(2).Find(What:="Segment 4", LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=True, SearchFormat:=False)
If Not aCell Is Nothing Then
aCell.Offset(0, 1).Value = qb.Range("B2")
Else
MsgBox "Segment 4 Not Found"
End If
qb.Range("B2:F2").Copy
aCell.Offset(0, 13).Select
ActiveCell.PasteSpecial
End With
End Sub
Is there a way I can loop through Column B in "Month" and match it to data in Column A in "Data" without having to write a search for each Segment?
Thanks in advance for your input!
How about a For Each loop going through column A of Data:
Sub Macro1()
' Macro1 Macro
' For post onto StackOverflow
Dim ws As Worksheet
Dim qb As Worksheet
Dim aCell As Range
Set ws = ThisWorkbook.Sheets("Month")
Set qb = ThisWorkbook.Sheets("Data")
qb.Activate
Dim dataCell As Variant
For Each dataCell In qb.Range(Cells(2, 1), Cells(qb.Cells(qb.Rows.Count, "A").End(xlUp).Row, 1))
With ws
Set aCell = .Columns(2).Find(What:=dataCell.Value, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=True, SearchFormat:=False)
If Not aCell Is Nothing Then
Range(aCell.Offset(0, 1), aCell.Offset(0, 5)).Value = Range(dataCell.Offset(0, 1), dataCell.Offset(0, 5)).Value
Else
MsgBox dataCell.Value & " Not Found"
End If
End With
Next dataCell
End Sub
Related
I have an excel workbook where an unknown amount of data from text files can be imported (the user will import as many text files as they feel necessary). I am attaching an identifier (1, 2, 3, etc) each time a text file is imported to the workbook. On the "Information Sheet" I have a form control combobox where the user selects the "initial data set" aka (1, 2, 3, etc) by selecting the identifier value from the dropdown. What I want to happen is when the user selects a value to specify the initial data set, this data set will get highlighted in grey on the "Data Importation Sheet" aka the sheet where all the data gets imported to. I think my code is close but it isnt working.
Here is my code for the Combobox:
Private Sub ComboBox1_Change()
Call Find_Initial_Data_Set
End Sub
And here is my code for highlighting the data in the "Data Importation Sheet" according to the value in cell E12 where my Combobox is located:
Sub Find_Initial_Data_Set()
Dim ws As Worksheet
Dim aCell As Range
Dim aCell1, aCell2, aCell3 As Range
Dim NewRange As Range
Dim A As String
Dim LastRow As Integer
Worksheets("Information Sheet").Activate
If Range("E12").Value <> "" Then
Set ws = Worksheets("Data Importation Sheet")
A = Worksheets("Information Sheet").Range("E12").Value
Worksheets("Data Importation Sheet").Activate
With ws
Set aCell = .Rows(1).Find(What:=A, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
End With
LastRow = Worksheets("Data Importation Sheet").Cells(Rows.Count, "A").End(xlUp).Offset(-1).Row
With ws
Set aCell1 = aCell.Offset(0, -1)
Set aCell2 = aCell.Offset(LastRow, 5)
Debug.Print aCell1.FormulaR1C1
Debug.Print aCell2.FormulaR1C1
Set NewRange = .Range(aCell1.Address & ":" & aCell2.Address)
Debug.Print NewRange.Address
End With
NewRange.Interior.ColorIndex = 15
Else
End If
End Sub
Here are some visuals of my excel book:
Data Importation Sheet where the data gets input (you cannot see the identifier in this pic but beneath the data I have a cell that says Identifier with the corresponding importation value beside it):
Information Sheet where the user selects the initial data set based on identifier:
And this is what I would like the Data Importation Sheet to look like after the user selects 1 (for example) for the initial data set:
Any advice would be greatly appreciated!
the code would be like this.
sheet's code
Private Sub ComboBox1_Change()
Call Find_Initial_Data_Set(ComboBox1.Text)
End Sub
module code
Sub Find_Initial_Data_Set(A As String)
Dim Ws As Worksheet
Dim aCell As Range, NewRange As Range
Dim LastRow As Integer
Set Ws = Worksheets("Data Importation Sheet")
With Ws
If A <> "" Then
Set aCell = .Rows(1).Find(what:=A, after:=.Range("a1"), LookIn:=xlValues, lookat:=xlPart)
If aCell Is Nothing Then
Else
Set aCell = aCell.Offset(, -1)
LastRow = .Range("a" & Rows.Count).End(xlUp).Row
Set NewRange = aCell.Resize(LastRow, 7)
NewRange.Interior.ColorIndex = 15
End If
End If
End With
End Sub
i rewrote your code somewhat
please single-step through code using F8 key
check if correct ranges are "selected" at "debug" lines
please update your post with findings
i suspect that the wrong cells are being referenced once the worksheet is partially populated
also, please refrain from using: ( ... this means, anyone reading this)
With ws
Set aCell = .Rows(1).Find(What:=A, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
End With
use this:
Set aCell = ws.Rows(1).Find(What:=A, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
it is shorter and more readable
use "with" convention only if it really simplifies the code a lot
see the end of the code for info that may help you
Sub Find_Initial_Data_Set()
Dim infoSht As Worksheet
Dim dataImpSht As Worksheet
Dim aCell As Range
' Dim aCell1, aCell2 As Range ' do not use ... aCell1 is declared as variant. not as range
Dim aCell1 As Range, aCell2 As Range, aCell3 As Range
Dim NewRange As Range
Dim A As String
Dim LastRow As Integer
Set dataImpSht = Worksheets("Data Importation Sheet")
Set infoSht = Worksheets("Information Sheet")
A = infoSht.Range("E12").Value
If A <> "" Then
Set aCell = dataImpSht.Rows(1).Find(What:=A, LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
dataImpSht.Activate ' debug .Select command fails if sheet is not visible
aCell.Select ' debug (this should highlight "aCell")
dataImpSht.Cells(dataImpSht.Rows.Count, "A").Select ' debug
dataImpSht.Cells(dataImpSht.Rows.Count, "A").End(xlUp).Select ' debug
dataImpSht.Cells(dataImpSht.Rows.Count, "A").End(xlUp).Offset(-1).Select ' debug
dataImpSht.Cells(dataImpSht.Rows.Count, "A").End(xlUp).Offset(1).Select ' debug
LastRow = dataImpSht.Cells(dataImpSht.Rows.Count, "A").End(xlUp).Offset(-1).Row
aCell.Select ' debug
aCell.Offset(0, -1).Select ' debug
aCell.Offset(LastRow, 5).Select ' debug
Set aCell1 = aCell.Offset(0, -1)
Set aCell2 = aCell.Offset(LastRow, 5)
aCell1.Select ' debug
aCell2.Select ' debug
Debug.Print aCell1.FormulaR1C1
Debug.Print aCell2.FormulaR1C1
Set NewRange = dataImpSht.Range(aCell1.Address & ":" & aCell2.Address)
NewRange.Select ' debug
Debug.Print NewRange.Address
NewRange.Interior.ColorIndex = 15
End If
'---------------------------------------------------------------------------
' check this out ... it may be what you need to use
Dim aaa As Range
Set aaa = dataImpSht.Cells(dataImpSht.Rows.Count, "A").End(xlUp).Offset(1)
aaa.Select
aaa.Range("a1").Select ' aaa can be thought off as the new top left corner
aaa.Range("b2").Select ' you can refer to cells in relation to aaa
Set aaa = aaa.Offset(4) ' and move position of aaa for each iteration
aaa.Range("a1").Select
aaa.Range("b2").Select
'---------------------------------------------------------------------------
End Sub
You need to change LastRow to the following as all you need is the row number:
LastRow = Worksheets("Data Importation Sheet").Cells(Rows.Count, "A").End(xlUp).Row - 1
I hope you can help. I have a some code below which works fine. What it does is opens up a dialog box allows a user to select an excel file, once this file is selected.
The code looks through the column headings find the Text "CountryCode" then cuts this column puts it into Column F then separates column F into new worksheets based on the country.
This issue I am facing is that sometimes the the column I want to cut contains the text "ClientField10" or "ClientField1"
So what I would like the macro to do is search the column headings for "CountryCode" if this is found fine execute the rest of the code.
If it is NOT found search for "CleintField10" then if found execute and if neither "CountyCode" or "CleintField10" is found search for "CleintField1" then execute the rest of the code
My code is below as always any help is greatly appreciated.
Sub Open_Workbook_Dialog()
Dim my_FileName As Variant
Dim my_Workbook As Workbook
MsgBox "Pick your TOV file" '<--| txt box for prompt to pick a file
my_FileName = Application.GetOpenFilename(FileFilter:="Excel Files,*.xl*;*.xm*") '<--| Opens the file window to allow selection
If my_FileName <> False Then
Set my_Workbook = Workbooks.Open(Filename:=my_FileName)
Call Sample(my_Workbook) '<--|Calls the Filter Code and executes
Call Filter(my_Workbook) '<--|Calls the Filter Code and executes
End If
End Sub
Public Sub Sample(my_Workbook As Workbook)
Dim ws As Worksheet
Dim aCell As Range, Rng As Range
Dim col As Long, lRow As Long
Dim colName As String
'~~> Change this to the relevant sheet
Set ws = my_Workbook.Sheets(1)
With ws
Set aCell = .Range("A1:BB50").Find(What:="CountryCode", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False)
'~~> If Found
If Not aCell Is Nothing Then
'~~> Cut the entire column
aCell.EntireColumn.Cut
'~~> Insert the column here
Columns("F:F").Insert Shift:=xlToRight
Else
MsgBox "Country Not Found"
End If
End With
End Sub
Public Sub Filter(my_Workbook As Workbook)
Dim rCountry As Range, helpCol As Range
With my_Workbook.Sheets(1) '<--| refer to data worksheet
With .UsedRange
Set helpCol = .Resize(1, 1).Offset(, .Columns.Count) '<--| get a "helper" column just at the right of used range, it'll be used to store unique country names in
End With
With .Range("A1:Q" & .Cells(.Rows.Count, 1).End(xlUp).Row) '<--| refer to its columns "A:Q" from row 1 to last non empty row of column "A"
.Columns(6).AdvancedFilter Action:=xlFilterCopy, CopyToRange:=helpCol, Unique:=True '<-- call AdvancedFilter on 6th column of the referenced range and store its unique values in "helper" column
Set helpCol = Range(helpCol.Offset(1), helpCol.End(xlDown)) '<--| set range with unique names in (skip header row)
For Each rCountry In helpCol '<--| iterate over unique country names range (skip header row)
.AutoFilter 6, rCountry.Value2 '<--| filter data on country field (6th column) with current unique country name
If Application.WorksheetFunction.Subtotal(103, .Cells.Resize(, 1)) > 1 Then '<--| if any cell other than header ones has been filtered...
Worksheets.Add Worksheets(Worksheets.Count) '<--... add new sheet
ActiveSheet.Name = rCountry.Value2 '<--... rename it
.SpecialCells(xlCellTypeVisible).Copy ActiveSheet.Range("A1") 'copy data for country under header
End If
Next
End With
.AutoFilterMode = False '<--| remove autofilter and show all rows back
End With
helpCol.Offset(-1).End(xlDown).Clear '<--| clear helper column (header included)
End Sub
Because I didn't get to test my code before, I made the silly mistake of using "If" instead of an "ElseIf" statements. I tested the below code and now it works.
Sub test()
Dim acell As Range
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets(1) 'define ws
Set acell = ws.Range("A1:BB50").Find(What:="CountryCode", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False) 'define acell as location of "countrycode"
If Not acell Is Nothing Then 'if address is found do the cut & insert of that column
acell.EntireColumn.Cut
Columns("F:F").Insert Shift:=xlToRight
ElseIf acell Is Nothing Then 'if address is not found redefine acell to look for "clientfield10"
Set acell = ws.Range("A1:BB50").Find(What:="ClientField10", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False)
If Not acell Is Nothing Then 'if address is found do the cut & insert
acell.EntireColumn.Cut
Columns("F:F").Insert Shift:=xlToRight
ElseIf acell Is Nothing Then 'If not found redefine acell again to look for "ClientField1"
Set acell = ws.Range("A1:BB50").Find(What:="ClientField1", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False)
If Not acell Is Nothing Then 'If found do cut and insert
acell.EntireColumn.Cut
Columns("F:F").Insert Shift:=xlToRight
Else: MsgBox "Country Not Found" 'If none can be found display msgbox
End If
End If
End If 'close all the If loops
End Sub
I will delete my old answer to make this thread easier to understand
I would like to ask if you can help with the code below. On every sheet in my workbook there is the same kind of a table, however on each sheet the table has different location and values. I need to go through all sheets, search for table values on every sheet and then do some other operations with the values. I use Find function to determine header of the table and subsequently table range. The Find function does not work properly though as it keeps found address of "Header" cell from the first sheet for every other sheet. Is there any way to reset the found header address value before looping to another sheet? Thank you in advance.
Sub FindInDynamicRanges()
Dim wb1 As Workbook
Dim ws As Worksheet
Dim FoundCell, FoundTab, TabEntries As Excel.Range
Dim FirstAddr As String
Dim FirstRow, LastRow As Long
Set wb1 = ThisWorkbook
'Find all occurences of any table value on all sheets in dynamic ranges
For Each ws In wb1.Worksheets
Set ws = ActiveSheet
'Find "Header" cell
Set FoundCell = ws.Columns(2).Find(What:="Header", LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
MsgBox FoundCell.Address
'Set number of first entry row and last entry row
FirstRow = FoundCell.Row + 1
LastRow = ws.Cells.Find(What:="*", After:=Range("A1"), LookAt:=xlPart, LookIn:=xlValues, SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, MatchCase:=False).Row
ws.Range("B" & FirstRow & ":B" & LastRow).Name = "TabEntries"
MsgBox Range("TabEntries").Address
With ws.Range("TabEntries")
Set LastCell = .Cells(.Cells.Count)
End With
Set FoundTab = ws.Range("TabEntries").Find(What:="*", After:=LastCell, LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not FoundTab Is Nothing Then
FirstAddr = FoundTab.Address
End If
Do Until FoundTab Is Nothing
'do some staff with found values
Set FoundTab = ws.Range("TabEntries").FindNext(After:=FoundTab)
If FoundTab.Address = FirstAddr Then
Exit Do
End If
Loop
Next ws
End Sub
as it keeps found address of "Header" cell from the first sheet for every other sheet.
That is because you are telling it to...
For Each ws In wb1.Worksheets
Set ws = ActiveSheet
You don't need that Set ws = ActiveSheet
When you say For Each ws, the ws is automatically initialized. So just remove the second line.
I have a large sheet. I have to set multiple filters in that sheet to columns headers in dynamic positions. Once the filters are set, I have to find the particular column in the sheet having the column header "Nov" and then obtain the sum of values in that column and import that particular sum value into a different worksheet.
I've written the code up until the part where i can set the filters to multiple columns, but I'm finding it difficult to find the column header and add that column. Below is the code I've written so far.
Sub Button2_Click()
Dim colName As Long
Dim colName1 As Long
Dim colName2 As Long
Dim r As Long
SearchV = Range("A8:DD8").Find(What:="Nov", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False).Column
lastrow = Cells(Rows.Count, SearchV).End(xlUp).Row
colName = Range("A8:DD8").Find(What:="Teams", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False).Column
colName1 = Range("A8:DD8").Find(What:="Items", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False).Column
colName2 = Range("A8:DD8").Find(What:="Domain", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False).Column
ActiveSheet.Range("$A$8:$DD$9999").AutoFilter Field:=colName, Criteria1:="ST Test", Operator:=xlOr, Criteria2:=""
ActiveSheet.Range("$A$8:$DD$9999").AutoFilter Field:=colName1, Criteria1:="Variance", Operator:=xlOr, Criteria2:="(Blanks)"
ActiveSheet.Range("$A$8:$DD$9999").AutoFilter Field:=colName2, Criteria1:="9S", Operator:=xlOr, Criteria2:="(Blanks)"
The column headers always start from the 8th row. Some uesless information is present in the rows above. So what I want is, suppose the column 'Nov' is in H row. The sum should be calculated from H9 to the end of the last row. I had used this formula when the column was in 'H' column.
Cells(lastrow + 1, colName3).Formula = "=SUBTOTAL(9,H9:H" & lastrow & ")"
But the column 'Nov' won't always be present in row 'H', so i'm not able to figure out how to change my code to pick the column dynamically.
Ensure that you fully qualify your objects and also put in a check whether .Find returns something or not. Here is an example.
Let's say your worksheet looks like this
Now try this code
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim aCell As Range, Rng As Range
Dim col As Long, lRow As Long
Dim colName As String
'~~> Change this to the relevant sheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
Set aCell = .Range("A8:DD8").Find(What:="Nov", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False)
'~~> If Found
If Not aCell Is Nothing Then
col = aCell.Column
colName = Split(.Cells(, col).Address, "$")(1)
lRow = .Range(colName & .Rows.Count).End(xlUp).Row
'~~> This is your range
Set Rng = .Range(colName & "8:" & colName & lRow)
Debug.Print Rng.Address
'~~> If not found
Else
MsgBox "Nov Not Found"
End If
End With
End Sub
Output
Sheets("DATA").Rows(2).Find(What:="Apple", LookIn:=xlValues, _
LookAt:=xlWhole).Offset(1, 0).Value = "=A3-B3"
Selection.FillDown
I want to find a column "Apple" in Row 2 and filldown with formula "A3-B3"
Would something like .value="=A3-B3".filldown work?
Thanks!
Further to my comments above, try this. I have commented the code. Do let me know if you find anything confusing...
Sub Sample()
Dim ws As Worksheet
Dim LRow As Long
Dim aCell As Range
'~~> Set this to the relevant sheet
Set ws = ThisWorkbook.Sheets("Data")
With ws
'~~> Find Last Row
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Find the cell which has "Apple"
Set aCell = .Rows(2).Find(What:="Apple", LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'~~> if found, then enter the formula till the last row IN ONE GO
If Not aCell Is Nothing Then
.Range(.Cells(3, aCell.Column), .Cells(LRow, aCell.Column)).Formula = "=A3-B3"
End If
End With
End Sub