Good evening. I am developing a subroutine for a project whereby the user is able to upload specific data from a separate workbook into the master. The routine will search through the chosen excel file for specific column headers and only copy/paste those desired columns to the master sheet. This is my first coding project and I think I have the process mostly sorted, however there is one bit of functionality that is eluding me: The specific column titles are moderately similar no matter the workbook, except they may vary between full name and abbreviation. For example the title of the column may be "AZM" or it may be "Azimuth". Alternatively one column title may be "N/S", "Northing" or "NS". There will never be multiple of these titles, just the one in the format that the workbook creator decided to go with.
My current code does not currently account for that:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False
Dim wb As Workbook
Dim filename As String, colName As String
Dim LRow As Long, LCol As Long
Dim pColName As String, MyHead(1 To 8) As String
Dim sCell As Range, PRng As Range
Dim col As Long, pCol As Long
MsgBox "Ensure plan includes MD/INC/AZM/TVD/NS/EW/VS/DLS"
With Application.FileDialog(msoFileDialogOpen) 'Open file explorer
.AllowMultiSelect = False 'Only allow one file to be chosen
.Filters.Add "Excel Files", "*.xlsx; *.xlsm; *.xls; *.xlsb", 1 'Limit selection options to excel files
If .Show Then
filename = .SelectedItems(1) 'Assign file path to variable filename
Set wb = Workbooks.Open(filename:=filename) 'Set selected Excel file to variable wb
MyHead(1) = "MD"
MyHead(2) = "Inc"
MyHead(3) = "Azimuth"
MyHead(4) = "TVD"
MyHead(5) = "N/S"
MyHead(6) = "E/W"
MyHead(7) = "VS"
MyHead(8) = "DLS"
If Not IsEmpty(ThisWorkbook.Worksheets("5D-Lite").Range("M33")) Then
LRow = Cells(Rows.Count, 13).End(xlUp).Row 'Find the last row of data in column M from previous plan
LCol = Cells(LRow, Columns.Count).End(xlToLeft).Column 'Find the last column of data in the last row
ThisWorkbook.Worksheets("5D-Lite").Range("M33:" & Col_Letter(LCol) & LRow).ClearContents 'Clear the contents of the range determined by the Last functions
End If
With wb.Worksheets(1)
For i = LBound(MyHead) To UBound(MyHead)
Set sCell = .Range("A1:R50").Find(What:=MyHead(i), LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False) 'Search for the desired directional plan items in column headers
If Not sCell Is Nothing Then
col = sCell.Column 'Located item's column number
pCol = i + 12 'Column number in master workbook to paste in
colName = Split(.Cells(, col).Address, "$")(1) 'Located item's column letter
pColName = Split(.Cells(, pCol).Address, "$")(1) 'Column letter in master workbook to paste in
LRow = FindLastNumeric() 'Find the final row with numeric data
Set PRng = .Range(sCell.Address & ":" & colName & LRow) 'Set total data range of desired column
wb.Activate
wb.Worksheets(1).Range(PRng.Address).Copy ThisWorkbook.Worksheets("5D-Lite").Range(pColName & "32") 'Copy contents of selected file to the 5D sheet
End If
Next
Range("M32:T" & LRow + 33).NumberFormat = "0.00" 'Assigns numeric formatting to the pasted data range
wb.Close SaveChanges:=False
Set wb = Nothing
End With
Else
MsgBox "No Plan Selected"
End If
End With
Application.ScreenUpdating = True
End Sub
Is there any way to modify the .Find function or the MyHead(i) variables to account for multiple possible variations on the same header name? Thanks for any ideas.
It looks to me like you need prepare some kind of a dictionary. A simple solution would be to have an Excel table which stores all the information, which is stored in an array on startup (for quicker references) and then used to translate inputs to outputs. It could look something like this:
POSSIBLE_SOURCE VALID_NAME
appl apple
apple apple
orng orange
orange orange
To use this you would search the source files for matches in POSSIBLE_SOURCE column, find corresponding value in VALID_NAME column and use the latter for whatever you need to do with the input row.
Related
On some difficult issue I am bumped in. And i guess it quite out of my knowledge, and I hope it is even possible to solve on some way.
ISSUE:
Two different workbooks: I am having one workbook with 10 sheets inside, with many formulas, dropdowns, calculations etc., and it is main version of the document which has to be filled with information.
Second workbook, or better to say another similar version to this workbook is like obsolete versions of main wb, where might be possible that some cells/format, or even sheet is missing, but in general almost the same from its structure.
PROCESS:
Sometimes the customers are not having the newest version of excel workbook, but still some of the obsolete versions (they are forgetting to use the newest version), and they are filling those fields inside those older versions and sending them back. The problem is, our ERP Software cant read the obsolete versions, because it is so adjusted to read only the newest version of the document. Meaning, it has to be manually checked every time when the document is sent back and finding discrepancies and copy/paste them into newest version of the document, and then upload it into ERP...
RESULT:
I am looking for some solution, with VBA or even formulas how to check every other workbook against "newest" and if there are any discrepancy and differences just to copy/paste everything from old to new version. When I say "everything" it means, all the fields, sheets, calculations, 1:1.
Unfortunately I am not writing any code or formula, because this is for me super advanced.
On the pic below is one example of one sheet how it looks like. There are lot of columns, calcs and so on.
Explanation:
To clarify bit better the content: inside one workbook is usually 10 sheets. 8x of them are the same (gas chambers from 1-8) and depending on the customer wishes, they can populated from 1-8. Sometimes 1 sometimes 5.
And range is from A1:Q54, full of data, tables, calculations, dropdowns, infos..
One sheet (9th) is customer details and last one (10th) is just instruction sheet with infos and screenshots.
So optimal would be to have macro that is taking everything from older versions, compare it with new one, and populate data that it finds, or on already given workbook or on new one but with the same content. I dont know if that is something possible.
An example of how to scan various cell ranges in a workbook and collate those that have values into a table. Second stage would be to transfer those values to the new format template.
Option Explicit
Sub extractAll()
Dim myfile As String, wb As Workbook, ws As Worksheet
Dim n As Long, rng1 As Range, rng2 As Range, msg As String
' select workbook to scan
With Application.FileDialog(msoFileDialogFilePicker)
.Title = "Please select a file"
.Show
.AllowMultiSelect = False
If .SelectedItems.Count = 0 Then 'If no folder is selected, abort
MsgBox "You did not select a file"
Exit Sub
End If
myfile = .SelectedItems(1)
End With
' collate data on sheet 1 and 2
Sheet1.Cells.Clear
Sheet1.Range("A1:E1") = Array("Sheet", "Addr", "Row", "Column", "Value")
Set rng1 = Sheet1.Range("A2")
Sheet2.Cells.Clear
Sheet2.Range("A1:D1") = Array("Addr", "Row", "Column", "Value")
Set rng2 = Sheet2.Range("A2")
' open workbook and scan worksheets
Set wb = Workbooks.Open(myfile, ReadOnly:=True)
For Each ws In wb.Sheets
If ws.Name Like "CH_recipe_#" Then
Call scanSheet(ws, rng1)
msg = msg & vbLf & ws.Name
ElseIf ws.Name = "Customer Details" Then
Call scanCustomer(ws, rng2)
msg = msg & vbLf & ws.Name
End If
Next
wb.Close savechanges:=False
MsgBox "Sheets scanned" & msg
End Sub
Sub scanSheet(ws As Worksheet, ByRef rng As Range)
Dim cell As Range, ar, s As String
Dim i As Long, n As Long
' old template layout
s = "D13,A15,C15,D15,E15,G15,J15,N15," ' process details
s = s & "E20:P24,E41:P41," ' Carrier, Gas 2-12, usage
s = s & "C45,D45,E45,G45,I45,K45,M45,N45,P45," ' exhaust line
s = s & "C48" ' notes and remarks
ar = Split(s, ",")
For i = 0 To UBound(ar)
For Each cell In ws.Range(ar(i))
If cell.Value <> "" Then
rng = ws.Name
rng.Offset(, 1) = cell.Address(0, 0)
rng.Offset(, 2) = cell.Row
rng.Offset(, 3) = cell.Column
rng.Offset(, 4) = cell.Value
Set rng = rng.Offset(1)
End If
Next
Next
Debug.Print ws.Name & " Done"
End Sub
Sub scanCustomer(ws As Worksheet, ByRef rng As Range)
Dim cell As Range, ar, s As String
Dim i As Long, n As Long
' old template layout
s = "B14:B25," ' contact details
s = s & "B28:B29," ' existing install
s = s & "B32:B35," ' hook up
s = s & "A38" ' remarks
ar = Split(s, ",")
For i = 0 To UBound(ar)
For Each cell In ws.Range(ar(i))
If cell.Value <> "" Then
rng = cell.Address(0, 0)
rng.Offset(, 1) = cell.Row
rng.Offset(, 2) = cell.Column
rng.Offset(, 3) = cell.Value
Set rng = rng.Offset(1)
End If
Next
Next
Debug.Print ws.Name & " Done"
End Sub
I have a workbook already made and it is set up specifically to create histograms on data read in from a separate program. When I pull the data into the workbook, it all goes into one sheet in my workbook. From here I need to split the data apart and sort it into specific tabs based on part number. I have 9 part numbers total and around 25,000 rows of data a day that needs to be sorted. Column A is the date, B is the serial number, C is the part number, D is a machine code, E is the static flow data, and F is a detail. I need to sort by Column C 9 potential part numbers which look like this "'111". "'123" etc with an apostrophe before each number. They are already in that format. The only data that needs to go to the corresponding worksheet is numbers from Column E. This is what I have so far but it doesn't work.
'For loop to filter through all the available part times and put the data in the correct tab
For i = 1 To 11
'PartType array is all 9 part types possible
Worksheets("Paste Data Here").AutoFilter Field:=3, Criteria1:=PartType(i) 'This is where it fails
Debug.Print ("Filtered")
Worksheets("Paste Data Here").SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Debug.Print ("Selected")
'InputRanges is where in each worksheet the data needs to go, this is established
'in another sub
'TabList is an array of each worksheet in the same order at the PartType array
ThisWorkbook.Sheets(TabList(i)).InputRanges(daterange).Select
ThisWorkbook.Sheets(TabList(i)).InputRanges(daterange).Paste
Debug.Print ("Pasted")
Application.CutCopyMode = False
Debug.Print ("i: " & i)
Debug.Print ("PartType(i): " & PartType(i))
Next i
Neither AutoFilter nor SpecialCells works like that for a worksheet.
You need to specify some kind of range to apply these methods to.
Dim ws As Worksheet
Set ws = Worksheets("Paste Data Here")
ws.UsedRange.AutoFilter Field:=3, Criteria1:=PartType(i)
ws.UsedRange.SpecialCells(xlCellTypeVisible).Copy ThisWorkbook.Sheets(TabList(i)).InputRanges(DateRange)
For i = 1 To 11
Debug.Print ("Searching Part: " & PartType(i))
Dim ws As Worksheet
Set ws = Worksheets("Paste Data Here")
ws.AutoFilterMode = False
Dim rng1 As Range
Set rng1 = Range("C:C").Find(PartType(i), , xlValues, xlWhole)
If Not rng1 Is Nothing Then
Dim lastrow1 As Long
lastrow1 = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Dim copyRange As Range
Set copyRange = ws.Range("E2:E" & lastrow1)
ws.UsedRange.AutoFilter Field:=3, Criteria1:=PartType(i)
copyRange.SpecialCells(xlCellTypeVisible).Copy ThisWorkbook.Sheets(TabList(i)).Range(InputRanges(daterange))
End If
Next i
I have a long list of words I need to compare against.
As an example fruit and vegetables that needs to be stored cold vs warmer:
Cold
strawberries
raspberries
lettuce
Warm(er)
cucumber
bell pepper
tomatoes
I have a sheet with products and need to loop it:
For Each cel In rng
If LCase(cel.Value) Like "*strawberries*" Or LCase(cel.Value) Like "*raspberries*" Or LCase(cel.Value) Like "*lettuce*" Then
msgbox "Cold"
ElseIf LCase(cel.Value) Like "*cucumber*" or LCase(cel.Value) Like "*bell pepper*" or LCase(cel.Value) Like "*tomato*" Then
msgbox "Warmer"
End If
Next cel
Is there any way I could this better? The syntax to test against all products will be very very long.
Could I somehow group/list them and make the syntax easier to maintain?
Example of the workbook:
To demonstrate what I meant with a wildcard match:
Sub Test()
Dim rng As Range, cl As Range
Dim Cold As Variant, Warm As Variant
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1:A4")
Cold = Array("*strawberries*", "*raspberries*", "*lettuce*")
Warm = Array("*cucumber*", "*bell pepper*", "*tomatoes*")
With Application
For Each cl In rng
If .IsNumber(.Match(True, .IsNumber(.Match(Cold, cl, 0)), 0)) Then
'Or: If UBound(Filter(.IsNumber(.Match(Warm, cl, 0)), True)) = 0 Then
MsgBox "Cold"
ElseIf .IsNumber(.Match(True, .IsNumber(.Match(Warm, cl, 0)), 0)) Then
MsgBox "Warm"
End If
Next
End With
End Sub
Alternatively, you could use regular expressions with word-boundaries:
Sub Test()
Dim rng As Range, cl As Range
Dim Cold As String, Warm As String
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1:A4")
Cold = "strawberries|raspberries|lettuce"
Warm = "cucumber|bell pepper|tomatoes"
With CreateObject("vbscript.regexp")
.IgnoreCase = True
For Each cl In rng
.Pattern = "\b" & Cold & "\b"
If .Test(cl) Then
MsgBox "Cold"
Else
.Pattern = "\b" & Warm & "\b"
If .Test(cl) Then MsgBox "Warm"
End If
Next
End With
End Sub
You can also, match both in any case and see if it's supposed to be a combination of warm and cold.
Here is a perfunctory system that would return the information you want from a list of produce.
Sub GetStorageInstruction()
' 187
Dim Veggie As Variant
Dim Storage As String
Dim Txt As String
Veggie = InputBox("Enter name of fruit or vegetable to store:", _
"Get storage instruction")
Veggie = Trim(Veggie)
If Len(Veggie) Then
Storage = StorageInstruction(Veggie)
If Len(Storage) Then
Txt = "Store " & Veggie & " at a " & Storage & " location."
Else
Txt = "Sorry, I couldn't find instructions on" & vbCr & _
"storage of """ & Veggie & """."
End If
MsgBox Txt, vbInformation, "Storage instructions"
End If
End Sub
Private Function StorageInstruction(ByVal Veggie As String) As String
' 187
' return vbNullString if not found
Dim ListRng As Range
Dim Fnd As Range ' found match
Dim C As Long ' column
' here items for "Cold" storage are in column A,
' items for "Cool" storage are in column B
Set ListRng = Range("A:B") ' adjust to suit
Set Fnd = ListRng.Find(Veggie, LookIn:=xlValues, Lookat:=xlWhole, MatchCase:=False)
If Not Fnd Is Nothing Then
' the return result is taken from the caption row (row 1)
' of the column in which a match was found
StorageInstruction = Cells(1, Fnd.Column).Value
End If
End Function
"Ordinarily", you wouldn't work with an InputBox because it's too error prone (typos) but with a validation list or combo box that is based on the same lists. But for the moment, if you are concerned about not finding "Bell peppers" (plural), consider either listing "Bell pepper" as well or modify the search to LookAt:=xlPart.
To make the above code work for you immediately, just type "Cold" in A1, "Cool" in B1 and a list of produce under each header. The code will return the header from the column where the item was found.
I see that you have now added a view of your worksheet. That is a much better base. Instead of the produce name, list a number from your columns C or D (whichever is unique), in my columns A and B, and enter that number in the InputBox. Once you implement that system you can modify the returned answer by using the number to VLOOKUP the product name so that the description appears in the answer along with the number you entered.
As an afterthought, the best way for you would probably be to just select the row you are interested in, click a button (or keyboard shortcut) and have the storage instruction pop up. But the presumption here is that you should be able to attach VBA code to your workbook.
No. Correct. I solved that with search for asparagus then search again in the same string for potatoes. But I know there will be false matches. There is no way around it. Let's just say, if there is a handful of false matches is better than looking through the full sheet manually (30-40 000 rows). – Andreas 1 hour ago
Here is an example of what I recommend. Feel free to go with other answers. If there are multiple matches then fill the cell with "Cold/Warm" as mentioend in the code comments below. This way you can simply filter on these and fix them manually.
Basic Preparation to test this
Create a master sheet in the file which has the code. Let's call it MasterList. The reason why we are doing this is so that it is easier to maintain and when you are distributing the code file, the masterlist is easily available. You can do version control on the file so that everyone uses the current version. Let's say the MasterList looks like this.
Let's say the file (as shown in your image) is called MyData.xlsx and the data is in Sheet1. Feel free to change it in the code below. It looks like this
Code
Option Explicit
Sub Sample()
Dim wsThis As Worksheet
'~~> This is the hidden sheet which has your master list in the file
'~~> which has the code
Set wsThis = ThisWorkbook.Sheets("MasterList")
Dim lRow As Long
Dim MasterList As Variant
With wsThis
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
MasterList = .Range("A2:B" & lRow).Value2
End With
Dim wb As Workbook
Dim wsThat As Worksheet
'~~> Change this to the workbook where the data needs to be checked
Set wb = Workbooks.Open("C:\Users\Siddharth Rout\Desktop\MyData.xlsx")
'~~> Change this to the workseet where the data needs to be checked
Set wsThat = wb.Sheets("Sheet1")
Dim rngToProcess As Range
With wsThat
'~~> Find last row in Col E which has names
lRow = .Range("E" & .Rows.Count).End(xlUp).Row
'~~> Identify your range
Set rngToProcess = .Range("E2:E" & lRow)
'~~> Insert a blank column for output
.Columns(6).Insert Shift:=xlToRight
End With
Dim SearchText As String
Dim aCell As Range, bCell As Range
Dim i As Long
'~~> Loop through the masterlist
For i = LBound(MasterList) To UBound(MasterList)
SearchText = MasterList(i, 1)
Set aCell = rngToProcess.Find(What:=SearchText, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
'~~> Get the Warm - Cold - Warm/Cold Status
aCell.Offset(, 1).Value = GetStatus(MasterList(i, 2), aCell.Offset(, 1).Value)
'~~> Search again for multiple occurences
Do
Set aCell = rngToProcess.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
aCell.Offset(, 1).Value = GetStatus(MasterList(i, 2), aCell.Offset(, 1).Value)
Else
Exit Do
End If
Loop
End If
Next i
End Sub
'~~> Common function to asign the values
'~~> If there are multiple matches then fill the cell with "Warm/Cold".
'~~> This way you can simply filter on these and fix them manually.
Private Function GetStatus(MasterStatus As Variant, CurrentStatus As String) As String
Dim newStatus As String
If MasterStatus = "Cold" Then
Select Case CurrentStatus
Case "Warm": newStatus = "Warm/Cold"
Case Else: newStatus = MasterStatus
End Select
ElseIf MasterStatus = "Warm" Then
Select Case CurrentStatus
Case "Cold": newStatus = "Warm/Cold"
Case Else: newStatus = MasterStatus
End Select
End If
GetStatus = newStatus
End Function
Output
When you run the above code you get the below output
Here is an alternative to my earlier answer. Install the code below in a standard code module and make some arrangement to call it, perhaps with a keyboard shortcut or even a button on the sheet. Then simply select an item (anywhere in the list, no particular column) and run the code. You don't need to enter anything.
Sub Storage_Instruction()
' 187
Const SKUClm As String = "D" ' change to point at the SKU column in 'Data'
Const DescClm As String = "E" ' change to point at the Description column in 'Data'
Const StgClm As String = "C" ' change to point at Storage Instruction column in WsList
Dim WsData As Worksheet
Dim WsList As Worksheet
Dim SKU As String ' SKU number from row R
Dim Desc As String ' Description from row R
Dim R As Long ' the selected row
Dim LookUpRng As Range ' in WsList
Dim Fnd As Range ' found match
Dim Storage As Variant
Dim Txt As String
Set WsData = Worksheets("Data") ' insert your data sheet's name here
Set WsList = Worksheets("Storage") ' change name to suit
With WsList
' my list has an extra column for 'Description'
' the storage instruction is in column C (=StgClm)
Set LookUpRng = .Range(.Cells(2, "A"), .Cells(.Rows.Count, StgClm).End(xlUp))
End With
If ActiveSheet Is WsData Then
R = Selection.Row
With WsData
SKU = .Cells(R, SKUClm).Value
Desc = .Cells(R, DescClm).Value
End With
Set Fnd = LookUpRng.Find(SKU, LookIn:=xlValues, Lookat:=xlWhole)
If Fnd Is Nothing Then
Txt = "Sorry, I couldn't find instructions for the" & vbCr & _
"storage of " & Desc & "(SKU " & SKU & ")."
Else
Storage = WsList.Cells(Fnd.Row, StgClm).Value
Txt = "Store " & Desc & " (SKU " & SKU & ") at " & String(2, vbCr) & _
String(8, Chr(32)) & UCase(Storage) & String(2, vbCr) & "temperature."
End If
End If
MsgBox Txt, vbInformation, "Storage instruction"
End Sub
For the setup you do need to specify the 3 constants at the top of the procedure and the names of the two worksheets that are referenced.
The list is a simple copy of the SKU column from your big list. In my test I also copied the the descriptions. You may find that way easier to fill the 3rd column, which holds the words "Cool" and "Cold" (or whatever else you want) against each item. The middle column isn't used and not required y the above code.
According to your description, the 'List' sheet should be Very Hidden. In the VB Editor's Project Browser, click on the sheet, bring up its properties and set the Visible property to xlVeryHidden. The sheet can be made visible only by changing this property back to xlVisible. The property setting is saved when you save the workbook.
I would like some help on the below if you can.
I'm working between 2 workbooks and I want from the first one to find the value of Cell("B6") which happens to be a date on the second Workbook in column B. Although it seems that the code finds the date when it comes to set it as a range it comes as empty. Can you please help me to see what I'm doing wrong.
I'm a novice in VBA and I'm trying with an online search to make my life easier.
Thank you in advance.
Sub Update_Forecast_2()
Dim myFile As String
Dim YourFolderPath As Variant
Dim FindString As Date
Dim newFile As String
FindString = CLng(Date)
Dim Rng As Range
YourFolderPath = "C:\Users\konstand\Desktop\Forecast"
ChDir YourFolderPath
myFile = Application.GetOpenFilename
If myFile = "False" Then Exit Sub
Workbooks.Open Filename:=myFile
newFile = Replace(myFile, YourFolderPath + "\", "")
Range("B6").Select
Workbooks("Forecast file.xlsm").Activate
Sheets("Forecast_Sort").Activate
Range("A1").FormulaR1C1 = myFile
Workbooks(newFile).Activate
Range("B6").Activate
FindString = Workbooks(newFile).Sheets("Forecast").Range("B6").Value
'MsgBox FindString
If Trim(FindString) <> "" Then
With Workbooks("Forecast file").Sheets("Forecast_Sort").Range("B:B")
Set Rng = .Find(What:=DateValue(FindString), _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Rng.Select
End If
Workbooks("Forecast file.xlsm").Activate
End With
End If
End Sub
Following Erjon's request in order to help you more to understand what I'm trying to do I attached 2 pictures and kind of explained something. I hope I helped and didn't make it more confusing.
So I have the main file on which I want to see the changes
Main File
Then I have the file from which I want to take the updated values every week if not more frequently. Be aware that this file every time will have a different name, such as "Wk09Update.xlsx", "Wk10Update.xlsx", "Wk11Update.xlsx", .......
Though before I go to the new file to copy and paste the new values I want on the main file from the date that the new file starts to copy the values from columns H,I, & J and paste them on top of the existing values in columns C, D, & E. Then I want to go to the new file and copy/paste the updated values from there to columns H,I, & J on the main file so I can see the diffenerces from a week to week update.
New File(Wk11Update.xlsx)
How it should be after Wk12Update
What I'm trying to do
Object Variable or With block Variable not set
First of all you need to make your code simple for example you have a lot of .Activate.
This will for sure in some point lead you into confusion.
you have to declare first all your worksheets and workbooks like this:
Sub Test()
dim book1 as workbook 'a workbook
dim book2 as workbook 'another workbook
dim SheetOfBook1 as worksheet
dim SheetOfBook2 as worksheet
set book1 = workbooks("NameOfWorkbook1.xlsm")
set book2 = workbooks("NameOfWorkbook2.xlsm")
set SheetOfBook1 = book1.worksheets("NameOfSheet")
set SheetOfBook2 = book2.worksheets("NameOfSheet")
'at this point you can check everything you want without activating something for example
SheetOfBook1.range("A1") = SheetOfBook2.Range("A1") 'or whatever
'if you want to check if a value in book1 exists in book2 then do a loop
dim cell as range
for each cell in SheetOfBook2.Range("A1:A100).Cells
If SheetOfBook1.range("A1") = Cell.Value Then
msgbox "I founded what you are searching for"
End If
Next Cell
End Sub
So you have to eliminate all this .activate, use loops etc. As for your example can you edit your question and can you illustrate with an image what you want to achieve?
Edit
If you want to open workbooks based on weeknumber i have this following code:
Sub Test()
Dim Main As Workbook
Dim Update As Workbook
Dim ForecastSort As Worksheet
Dim Forecast As Worksheet
Dim CheckIfOpen
Dim WeekNumber As String
Dim FirstDayInWeek
Dim FirstDayOfWeekRow As Long
Dim lRowUpdate As Long
Set Main = Workbooks("Main.xlsm")
Set ForecastSort = Main.Worksheets("Forecast_Sort")
'The code below will open the workbook which for name has the number week of today date automatically----------------------------------------------
WeekNumber = WorksheetFunction.WeekNum(Date) + 1 'The requested week
CheckIfOpen = IsWorkBookOpen("C:\Users\Erjon-PC\Desktop\Forecast\Wk" &
WeekNumber & "Update.xlsx") 'Checks if the update workbook is opened or not
FirstDayInWeek = Date - Weekday(Date, vbUseSystem) + 2 'First day of requested week
FirstDayOfWeekRow = ForecastSort.Range("B:B").Find(FirstDayInWeek).Row 'Finds the row of the start day of the requested week in main book
If CheckIfOpen = True Then
Set Update = Workbooks("Wk" & WeekNumber & "Update.xlsx")
Else
Set Update = Workbooks.Open("C:\Users\Erjon-PC\Desktop\Forecast\Wk" & WeekNumber & "Update.xlsx")
End If
'---------------------------------------------------------------------------------------------------------------------------------------------------
Set Forecast = Update.Worksheets("Forecast")
lRowUpdate = Forecast.Cells(Forecast.Rows.Count, "W").End(xlUp).Row 'Last row in column W in update book
Forecast.Range("W2:Y" & lRowUpdate).Copy
ForecastSort.Range("H" & FirstDayOfWeekRow).PasteSpecial xlPasteValues
Update.Close savechanges:=False
End Sub
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
The above code will open the workbook that has the week number in it's name, today it will open Wk11Update.xlsx, the next week it will open Wk12Update.xlsx.
If you want to open books that has for name future dates just add +1 or more to this code:
WeekNumber = WorksheetFunction.WeekNum(Date) + 1 'The requested week
Then in the opened book it will find last row with data in the column W, it will copy 3 column starting from W, and paste them in the column H of main book. The data will be pasted in the row where the first day of requested week is.
Is there any way to automatically arrange this data
Into this
Using excel/google sheets/etc. Basically I have a huge list of files (second column) that I need to map to it's respective folder (first column ID).
What I need, is to copy column A data down, but only to the blank cells immediately below, and then do it again for the new folder id, and so on.
I happen to have a macro that prompts the user which column to copy data down. See the below (Note you may need to tweak as necessary):
Sub GEN_USE_Copy_Data_Down()
Dim screenRefresh$, runAgain$
Dim lastRow&, newLastRow&
Dim c As Range
Dim LastRowCounter$
Dim columnArray() As String
screenRefresh = MsgBox("Turn OFF screen updating while macro runs?", vbYesNo)
If screenRefresh = vbYes Then
Application.ScreenUpdating = False
Else
Application.ScreenUpdating = True
End If
Dim EffectiveDateCol As Integer
LastRowCounter = InputBox("What column has the most data (this info will be used to find the last used row")
CopyAgain:
With ActiveSheet
lastRow = .UsedRange.Rows.Count
End With
' THIS WILL ASK THE USER TO SELECT THE COLUMN TO COPY DATA DOWN
MsgBox ("Now, you will choose a column, and that column's data will be pasted in the range" & vbCrLf & "below the current cell, to the next full cell")
Dim Column2Copy As String
Column2Copy = InputBox("What columns (A,B,C, etc.) would you like to copy the data of? Use SPACES, to separate columns")
columnArray() = Split(Column2Copy)
Dim startCell As Range
For i = LBound(columnArray) To UBound(columnArray)
Debug.Print i
Column2Copy = columnArray(i)
Set startCell = Cells(1, Column2Copy).End(xlDown)
Do While startCell.row < lastRow
If startCell.End(xlDown).Offset(-1, 0).row > lastRow Then
newLastRow = lastRow
Else
newLastRow = startCell.End(xlDown).Offset(-1, 0).row
End If
Set CopyFrom = startCell
Range(Cells(startCell.row, Column2Copy), Cells(newLastRow, Column2Copy)).Value = CopyFrom.Value
Set startCell = startCell.End(xlDown)
Loop
Next i
If screenRefresh = vbYes Then
Application.ScreenUpdating = True
Else
Application.ScreenUpdating = True
End If
End Sub
I wrote it a while ago, so it might be able to have lines removed/combined, but it should work (assuming you're trying to just copy data down column A).
In Excel, select the left-hand column, HOME > Editing, Find & Select, Go to Special..., check Blanks (only), OK, then select one of the chosen cells, =, Up, Ctl+Enter.