So I need a bit of help with an existing macro.
I need to split a workbook's multiple worksheets into multiple files (not based on worksheet name).
The project: It deals with very sensitive HR/performance data, and I need to send 1000s of employees' data to their individual managers (about 100 managers who can only see their team's data, and no one else's), so I need about 100 files split (1 for each manager).
The file:
- Many different tabs, separated by role.
- First column is a unique identifier made by concatenating the Manager's name with the job title ex. John Stevens_Office Manager
The task: John Stevens will have team members in many different job roles, and needs all that data in one file, separated into tabs by job role. My current macro does half of this (splits the file, but does not unite).
It also doesn't delete out the other tabs from the file...and its a big file with about 50 tabs. Even just some help deleting the other tabs would be greatly appreciated. Also, the data is populated via VLookup, and every time it splits a file it gives me a message asking if I want to update the links? Can the updates be turned on permanently so it splits without any manual input?
Below is some sample data. Please keep in mind that the actual file is far more complex (at least 50 columns)
Sample Data
Sub SplitWB()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
ActiveWorkbook.Save
Dim OutputFolderName As String
OutputFolderName = ""
Set myDlg = Application.FileDialog(msoFileDialogFolderPicker)
myDlg.AllowMultiSelect = False
myDlg.Title = "Select Output Folder for Touchstone Files:"
If myDlg.Show = -1 Then OutputFolderName = myDlg.SelectedItems(1) & "\" Else Exit Sub
Set myDlg = Nothing
Application.CutCopyMode = False
'''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''
Dim d As Object, c As range, k, tmp As String, unique(500)
i = 0
With ActiveSheet
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set d = CreateObject("scripting.dictionary")
For Each c In range(Cells(1, 1), Cells(lastRow, 1))
tmp = Trim(c.Value)
If Len(tmp) > 0 Then d(tmp) = d(tmp) + 1
Next c
For Each k In d.keys
Debug.Print k, d(k)
i = i + 1
unique(i) = k
Next k
UniqueCount = i
'start deleting
For i = 1 To UniqueCount
'Actions for new workbook
wpath = Application.ActiveWorkbook.FullName
wbook = ActiveWorkbook.Name
wsheet = ActiveSheet.Name
ActiveWorkbook.SaveAs Filename:=OutputFolderName & unique(i), FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
For j = 1 To lastRow
If range("A" & j) <> "" And range("A" & j) <> unique(i) Then
Rows(j).Delete
j = j - 1
End If
Next
'hide helper columns
' If HideC = False And DeleteC = True Then
Columns("A:D").Hidden = True
' End If
'
range("E8").Select
'Select Instructions tab
'Worksheets("Guidelines").Activate
'Save new workbook
ActiveWorkbook.Close SaveChanges:=True
Workbooks.Open (wpath)
'ActiveWorkbook.Close False
Workbooks(wbook).Activate
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox ("Macro has completed successfully!" & vbNewLine & vbNewLine & "Generated files can be found in the following directory:" & vbNewLine & OutputFolderName)
End Sub
Thank you! Have a great day!
Partial Answer: Put this at the top of your code: application.AskToUpdateLinks = False and this at the end application.AskToUpdateLinks = true.
So i think you have a lot of extra code that may not be needed. i'm going to start out small b/c i'm not sure i fully understand the task at hand.
First, i'm going to create an array for all names in column A. Next, i'm going to iterate through the array just for the unique values
Sub SplitWB()
Dim namesArray As Variant
Dim uniqueDict As New dictionary
namesArray = Range("a1:a4") 'hardcoded the range for now
Set uniqueDict = New dictionary
For x = LBound(namesArray) To UBound(namesArray)
If Not uniqueDict.Exists(x) Then uniqueDict.Add x, namesArray (x, 1)
Next x
End Sub
The above may not do anything for you just yet, but i notice you're doing unique for loops, etc which aren't necessary. Just trying to condense your code for ease of debugging.
Once you respond to this, we can work on the next part (you may want to update your code if you use my solution above to create a unique dictionary)
Related
I was wondering if anyone might be able to help me with this problem;
I have a large table. For all the rows in column F that meet a condition (must have a value of 89), I want to select the corresponding rows in columns A, H, and I. I then want to take these rows and export them as a csv file, and the file must be overwritten if it already exists.
For example, Let's say my table looks like;
F A B C H I
89 45 4 3 6 2
43 23 4 5 4 2
89 3 6 5 65 7
22 43 6 6 2 4
89 56 9 9 35 2
So as there are 3 rows in column F that meets the condition and the corresponding column A, H, and I rows have the values (45, 6, 2), (3, 65, 7) and (56, 35, 2) I want my exported file to look something like this;
**A H I**
45 6 2
3 65 7
56 35 2
I am having issues with 2 things:
being able to select only the specific cells for the SAME rows in the three wanted columns. Most of the help I found on the internet work only for choosing 1 specific cell, or entire columns. Given that I don't know which rows in column F will meet the condition, I cannot manually choose the corresponding cells in columns A, H, and I, as I don't know the row numbers.
My exported file won't act right; it either cannot overwrite (code1) or it keeps overwriting over and over and opens new workbooks when I run the code (code 2)
I have been trying back and forth for some time, and searched through the internet for anything that might help, but I cannot get it to work. As of now I have 2 different codes, that I've been trying to make work, but neither of them do.
The first code is:
Private Sub CommandButton1_Click()
Dim TransferExport As Integer
Dim u As Integer
Dim x As Integer
Dim y As Integer
Dim data As String
For i = 2 To 18288
If Sheets("Base").Cells(i, 6).Value = "89" Then
u = Sheets("Base").Cells(i, 1).Value
If Sheets("Base").Cells(i, 6).Value = "89" Then
x = Sheets("Base").Cells(i, 8).Value
If Sheets("Base").Cells(i, 6).Value = "89" Then
y = Sheets("Base").Cells(i, 9).Value
End If
End If
End If
TransferExport = FreeFile
data = data & Sheets("Base").Cells(1, 1) & u & " ; "
data = data & Sheets("Base").Cells(1, 8) & x & " ; "
data = data & Sheets("Base").Cells(1, 9) & y & " ; "
Open "C:\Users\bruger1\Documents\Uni\TransferExport.csv" For Append As
#TransferExport
Print #TransferExport, u, x, y
Close #TransferExport
Next
MsgBox "Your file has been exported"
End Sub
^This is my first code. Please note that I am aware that for my "If-Then" selections of u, x, and y, I am selecting the entire column which is of course not what I want, but I cannot find a way to make it select only the corresponding row. While it does run, it cannot run completely as there are too many rows (18288) and the rows that it does manage to pull out simply all say "0", nor does it pull out the top row in each column as I specified in the data strings (the top row is the column names). I tried to do like this;
Dim rw As Range
Set rw = Sheets("Base").Range("F:F")
For i = 2 To 18288
If rw = "89" Then
u = Sheets("Base").Cells(rw, 1).Value
But this wont work. The other problem with this code is, that it won't overwrite the file if it already exists and instead just refuses to run.
The second code that I've tried is;
Private Sub CommandButton1_Click()
Dim rng As Range
Dim cell As Range
Dim data As String
Set rng = Range("F2:F18288")
For Each cell In rng
If cell.Value = "89" Then
Sheets("Base").Cells(cell, "A").Select
Sheets("Base").Cells(cell, "H").Select
Sheets("Base").Cells(cell, "I").Select
End If
Selection.Copy
data = "C:\Users\bruger1\Documents\Uni\TransferExport.csv"
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs Filename:=data, _
FileFormat:=xlCSV, CreateBackup:=False, local:=True
Application.DisplayAlerts = False
ActiveWorkbook.Close
Application.DisplayAlerts = True
Next
MsgBox "Your file has been exported"
End Sub
I have several problems with this one; first, when I click the command button it will do different things for everytime I click? Sometimes it will continuously ask me if I want to overwrite the existing file, and also open a new document. Everytime I click yes it opens a new document and immediately asks me the same thing. If I click no or cancel it gives me a run-time error "1004". Sometimes it will export the file but also open a new workbook with a random value from my table which I did not try to pull out? Meanwhile the actual exported file "TransferExport" simply has single number "1" written in cell A1.
As said, I have been trying back and forth with any help I could find on the internet but nothing has worked so far. Any help would be greatly appreciated.
Something like this is what you're looking for:
Sub tgr()
'Declare variables
Dim wb As Workbook
Dim wsData As Worksheet
Dim wsTemp As Worksheet
Dim sCSVPath As String
Dim sCSVName As String
Dim sSearchCol As String
Dim vCriteria As Variant
'Turn off these items to run code faster, prevent "screen flickering", and ignore warnings (such as if you want to override an existing file)
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
'Set variables
Set wb = ActiveWorkbook
Set wsData = wb.Sheets("Base") 'This is the sheet containing the original data
Set wsTemp = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
sCSVPath = Environ("UserProfile") & "\Documents\Uni\" 'This is the folder path where the CSV file will be stored (automatically gets logged in user's username)
sCSVName = "TransferExport.csv" 'Name of the CSV file
sSearchCol = "F" 'Column in the original data to search
vCriteria = 89 'Critiera to search for in the specified column
'Work with the specified column
With wsData.Range(wsData.Cells(1, sSearchCol), wsData.Cells(wsData.Rows.Count, sSearchCol).End(xlUp))
'Filter for the specified criteria
.AutoFilter 1, vCriteria
'Copy relevant columns (A, H, and I) to the temp worksheet as values only
Intersect(.EntireRow, .Parent.Range("A:A,H:I")).Copy
wsTemp.Range("A1").PasteSpecial xlPasteValues
'Remove the filter
.AutoFilter
End With
'Move the temp sheet to its own workbook and save it as a CSV file and close it
'Because we turned off item DisplayAlerts, this will automatically overwrite the file if it already exists
wsTemp.Move
ActiveWorkbook.SaveAs sCSVPath & sCSVName, xlCSV
ActiveWorkbook.Close False
'Turn items back on
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
End Sub
Try This, please read the comments and try to understand everything happening in the code, feel free to ask questions:
Private Sub CommandButton1_Click()
Dim data As String, lastRow As Long, i As Long
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Set wk = ThisWorkbook
'New Workbook
Workbooks.Add
Set awk = ActiveWorkbook
'Copy all data to new Workbook
wk.Sheets("Base").Columns("A:F").Copy
awk.Worksheets(1).Range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
'Find the lastRow in this data based on Column F (6)
lastRow = awk.Worksheets(1).Cells(Excel.Rows.Count, 6).End(Excel.xlUp).Row
'Loop and Remove any Row where F is NOT "89"
For i = lastRow To 1 Step -1
If awk.Worksheets(1).Cells(i, 6).Value <> "89" Then
awk.Worksheets(1).Cells(i, 6).EntireRow.Delete
End If
Next
'Delete columns we dont want
awk.Worksheets(1).Columns("B:G").Delete Shift:=xlToLeft
'Save/Ovewrite It, Close it.
data = "C:\Users\bruger1\Documents\Uni\TransferExport.csv"
awk.SaveAs Filename:=data, FileFormat:=xlCSV, AccessMode:=xlExclusive, _
ConflictResolution:=Excel.XlSaveConflictResolution.xlLocalSessionChanges
Application.Calculation = xlCalculationAutomatic
awk.Close
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox "Your file has been exported"
End Sub
I wrote a small VBA macro to compare two worksheets and put unique values onto a new 3rd worksheet.
The code works, but every time I use if excel goes "not responding" and after 30-45sec comes back and everything worked as it should.
Can I make this faster and get rid of the "not responding" issue? is it just my computer not being fast enough?
I start with about 2500-2700 rows in each sheet I'm comparing.
Sub FilterNew()
Dim LastRow, x As Long
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "New" 'Adds a new Sheet to store unique values
Sheets(1).Rows("1:1").Copy Sheets("New").Rows("1:1") 'Copies the header row to the new sheet
Sheets(1).Select
LastRow = Range("B1").End(xlDown).Row
Application.ScreenUpdating = False
For Each Cell In Range("B2:B" & LastRow)
x = 2 'This is for looking through rows of sheet2
Dim unique As Boolean: unique = True
Do
If Cell.Value = Sheets(2).Cells(x, "B").Value Then 'Test if cell matches any cell on Sheet2
unique = False 'If the cells match, then its not unique
Exit Do 'And no need to continue testing
End If
x = x + 1
Loop Until IsEmpty(Sheets(2).Cells(x, "B"))
If unique = True Then
Cell.EntireRow.Copy Sheets("New").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
End If
Next
Application.ScreenUpdating = True
End Sub
This belongs in Code Review, but here is a link
http://www.excelitems.com/2010/12/optimize-vba-code-for-faster-macros.html
With your code your main issues are:
Selecting/Activating Sheets
Copy & pasting.
Fix those things and youll be set straight my friend :)
instead of a do...loop to find out duplicate, I would use range.find method:
set r = SHeets(2).range("b:b").find cell.value
if r is nothing then unique = true else unique = false
(quickly written and untested)
What about this (it's should help):
Sub FilterNew()
Dim Cel, Rng As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Sheets.Add(After:=Sheets(Sheets.Count)).Name = "New" 'Adds a new Sheet to store unique values
Sheets(1).Rows("1:1").Copy Sheets("New").Rows("1:1") 'Copies the header row to the new sheet
Set Rng = Sheet(1).Range("B2:B" & Sheet(1).Range("B1").End(xlDown).Row)
For Each Cel In Rng
If Cel.Value <> Sheet(2).Cells(Cel.Row, 2).Value Then Cel.EntireRow.Copy Sheets("New").Range("A" & Rows.Count).End(xlUp).Offset(1, 0) ' The only issue I have with this is that this doesn't actually tell you if the value is unique, it just tells you ins not on the same rows of the first and second sheet - Is this alright with you?
Next
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I'm trying to build a new VBA function for Excel. I've got a book of sheets with a front page that always loads first, on this page I've got a combo box that lists all the other sheets in the book and a nice extract button that will pull out the chosen sheet to a new book. (Thanks to those here who helped with that). Now I need a new function that will use the same combo box, but instead only extract a small subset of the chosen sheet.
Unfortunately, that subset isn't on the same rows for every sheet, nor is the number of rows the same (so one sheet, the subset might be 10 rows, on another it might be 12, on another it might be 20, etc etc etc).
On the plus side, there are merged rows (from column A to G) at the start and end of each subset - with specific text, which could be used to search for.
After some back and forth, I've got a better bit of code that I think is almost working:
Sub ZCPS_Extract()
Dim StartRow
Dim EndRow
Dim Zws As Worksheet
Dim wbkOriginal As Workbook
Set wbkOriginal = ActiveWorkbook
StartRow = 1
EndRow = 1
'sets site details into the header of the ZCPS checksheet
Worksheets(Sheet1.CmbSheet.Value).Range("B3").Value = Worksheets("front page").Range("E6")
Worksheets(Sheet1.CmbSheet.Value).Range("D3").Value = Worksheets("front page").Range("N6")
Worksheets(Sheet1.CmbSheet.Value).Range("F3").Value = Worksheets("front page").Range("K6")
Set Zws = Sheets(Sheet1.CmbSheet.Value)
'selects ZCPS block from select estate sheet
StartRow = (Zws.Cells.Find("**** ZCPS Installation").Row) + 1
EndRow = (Zws.Cells.Find("**** Aztec Hotfixes").Row) - 1
'copy above block and paste into Z-MISC starting at row 5
Worksheets(Sheet1.CmbSheet.Value).Range(Cells(StartRow, 1), Cells(EndRow, 7)).Copy Worksheets("Z-MISC").Range("A5")
With ActiveWorkbook.Sheets("Z-MISC")
.Copy
ActiveWorkbook.SaveAs _
"C:\temp\" _
& ActiveWorkbook.Sheets("Z-MISC").Cells(3, 2).Text _
& " ZCPS CheckSheet " _
& Format(Now(), "DD-MM-YY") _
& ".xlsm", _
xlOpenXMLWorkbookMacroEnabled, , , , False
End With
'code to close the original workbook to prevent accidental changes etc
Application.DisplayAlerts = False
wbkOriginal.Close
Application.DisplayAlerts = True
End Sub
It's error on the line for copying, I'm getting a runtime error of "Application-defined or object-defined error" which to my limited knowledge isn't helping me. Any assistance/pointers/suggestions are welcomed.
Sub ismerged()
Dim start As Integer, finish As Integer
For i = 1 To Range("A655").End(3).Row + 1
If Cells(i, "A").MergeCells = True Then
start = i
Exit For
End If
Next
For i = start To Range("A655").End(3).Row + 1
If Cells(i, "A").MergeCells = True Then
finish = i
End If
Next
MsgBox start
MsgBox finish
End Sub
Then I guess you can select your data as you wish.
I'm not sure about the way you reference your sheet. I will assume 'comboboxvalue' contains the name or the number of the sheet you are selecting. Your code should be something like the following.
Sub Z_Extract()
Dim StartRow
Dim EndRow
Dim ws As Worksheet
Set ws = Sheets(comboboxvalue)
StartRow = ws.Cells.Find("**** ZC").Row
EndRow = ws.Cells.Find("****").Row
'Im assuming you have values up to column G
ws.Range(ws.Cells(StartRow, 1), Cells(EndRow, 7)).Copy
'Now that you have the correct Range selected you can copy it to your new workbook
'SelectedRange.Copy Etc.....
'Cleanup
Set ws = Nothing
End Sub
Got it working.
Set Zws = Sheets(Sheet1.CmbSheet.Value)
'selects ZCPS block from selected estate sheet
StartRow = (Zws.Cells.Find("**** ZCPS Installation").Row)
EndRow = (Zws.Cells.Find("**** Aztec Hotfixes").Row) - 1
'copy above block and paste into Z-MISC starting at row 10
Sheets(Sheet1.CmbSheet.Value).Activate
ActiveSheet.Range(Cells(StartRow, 1), Cells(EndRow, 7)).Select
Selection.Copy
Sheets("Z-MISC").Select
Range("A10").Select
ActiveSheet.Paste
I am trying to automate a spreadsheet to transfer data from one sheet to another sheet depending on what the first 3 characters of the data is. So for example, for the data NDX 12/31/2012 P2600, I would like it to be placed in the NDX sheet. So I have an array (desArr()) that splits that data into different positions of the array, such that desArr(0) contains "NDX", desArr(1) contains "12/31/2012" and so on.
The part I am having trouble with is moving the data to the respective sheets. Specifically, I need a variable reference to these spreadsheets. For instant, take the NDX sheet. I know I can just do NDX.cells(1,1).Paste or Worksheets(NDX.Name).Cells(1,1).Paste and that would work, but what if I want to do that for multiple sheets? I could obviously use If statements to define each different instance, but I wanted to shorten my code. Hence, I am trying to make the reference to the sheet objects variable, i.e. desArr(0).Name, but it returns with an error (which I understand why). Anyone with suggestions on how to achieve this? I know one solution is to just use the name property of the worksheet, but I wanted to avoid the chance of my code failing if someone changed the name of the sheets.
So perhaps like:
Dim desArr() As String, desInfo As String, opType As String
Dim rNum As Long, cNum As Long, i As Long
Dim wb As Workbook
Dim ws As Worksheet
Dim sortRng As Range, findRng As Range
Dim j As Integer 'Throw away after testing
Dim test As String 'Throw away after testing
Dim k As Integer 'Throw away after testing
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set wb = ThisWorkbook
Set ws = wb.Worksheets(Import.Name)
With ws
rNum = .Range("C1048576").End(xlUp).Row
cNum = 6 'Number of used columns starting from left
Set sortRng = .Range(.Cells(3, 2), .Cells(rNum, cNum))
'Sort range according to Type and Description
sortRng.Sort _
Key1:=.Range("B1"), _
Key2:=.Range("C1")
'Apply conditional formatting
With sortRng.Columns(2)
.FormatConditions.AddUniqueValues
.FormatConditions(.FormatConditions.Count).SetFirstPriority
.FormatConditions(1).DupeUnique = xlDuplicate
With sortRng.Columns(2).FormatConditions(1)
.Interior.PatternColorIndex = xlAutomatic
.Interior.Color = 13551615
.Interior.TintAndShade = 0
.StopIfTrue = False
End With
End With
For i = 0 To (rNum - 2)
With sortRng.Cells(i + 1, 2)
If .DisplayFormat.Interior.Color = "13551615" Then
j = 0
While (.Value = .Offset(j + 1, 0).Value And .Offset(0, 1).Value = .Offset(j + 1, 1).Value)
j = j + 1
Wend
If (j <> 0) Then 'There are duplicates
End If
End If
'Converting the description to format used for classification
If .Offset(0, -1) = "Ext Option" Then
desArr = Split(.Value, " ")
If Not (Left(.Value, 3) = "SX5" Or Left(.Value, 3) = "UKX") Then
'check if it's a call or put
If Left(desArr(3), 1) = "C" Then
opType = "Call"
ElseIf Left(desArr(3), 1) = "P" Then
opType = "Put"
Else
opType = "N/A"
End If
desInfo = Format(desArr(2), "mmmdd") & " " & Right(Trim(desArr(3)), Len(Trim(desArr(3))) - 1) & " " & opType
Else
'check if it's a call or put
If Left(desArr(2), 1) = "C" Then
opType = "Call"
ElseIf Left(desArr(2), 1) = "P" Then
opType = "Put"
Else
opType = "N/A"
End If
desInfo = Format(desArr(1), "mmmdd") & " " & Right(Trim(desArr(2)), Len(Trim(desArr(2))) - 1) & " " & opType
End If
End If
End With
Next i
End With
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Except that NDX would have to be variable as which worksheet to move the data to depends on the data.
You can use the codename property of the worksheets. If you use NDX.Cells(1,1), NDX is the codename of the sheet. simply search all worksheets, e.g.:
Function GetWorksheet(byval withCodename as String) as Worksheet
Dim sheetVar as Worksheet
For each sheetVar in ThisWorkbook.Worksheets
If sheetVar.CodeName = withCodename Then
Set GetWorksheet = sheetVar
End if
Next
End Function
You could:
Prevent user from renaming sheets
You wrote: "I wanted to avoid the chance of my code failing if someone changed the name of the sheets."
Well, the user can't do this:
If you protect the workbook. You can do this manually in the ribbon (Review > Changes > Protect workbook), or programmatically like this:
ThisWorkbook.Protect 'optionally, add a password -- see documentation for Protect
This will entirely prevent the user from changing sheet names.
Here an absolute beginner at any form of coding, this is the first time ever I try to use VBA.
I have managed after a week and a half of searching and testing and learning to reach the below posted code and I have hit a WALL (and I'm not even done yet!)
What I am trying to achieve:
Compare the data in sheet1 with the data in sheet2 found in Columns K respectively A (there are ca. 55.000 rows in K and 2500 in A) the data might repeat itself as these are product codes and it's ok as at the end of this I want to be able to see which ones have expired.
so .. If K = A then it has to copy adjacent values found in Sheet2 - columns O, P & Q and Paste them in Sheet2 - Columns O, P & Q and if no match is found then right not found. In the Example below I have only tried to copy Q, it would probably take forever if I tried adding O & P.
(Note: I have found this code in one of the forms here and used it after trying different other ways with select/ Copy/ Paste etc. but none have worked)
Later I would like to try adding another column in Sheet1 and based on the Date which will be copied to Sheet1 and into column P populate it with Expired or Soon to be expired depending on the case, but this is an entire different story and I haven't even begun thinking how to do it.
The problem is that my current code takes over an hour and it's still not finished yet while I am writing this!!! And I do not understand where have I gone wrong ....
Dim lastRow1 As Long
Dim lastRow2 As Long
Dim tempVal As String
lastRow1 = Sheets("Sheet1").Range("K" & Rows.Count).End(xlUp).Row
lastRow2 = Sheets("Sheet2").Range("A" & Rows.Count).Row
For sRow = 2 To lastRow1
tempVal = Sheets("MatCode").Cells(sRow, "A").Text
For tRow = 2 To lastRow2
If Sheets("Sheet1").Cells(tRow, "K") = tempVal Then
Sheets("Sheet1").Cells(tRow, "Q") = Sheets("Sheet2").Cells(sRow, "Q")
End If
Next tRow
Next sRow
Dim match As Boolean
'now if no match was found, then put NO MATCH in cell
For lRow = 2 To lastRow2
match = False
tempVal = Sheets("Sheet1").Cells(lRow, "K").Text
For sRow = 2 To lastRow1
If Sheets("Sheet2").Cells(sRow, "A") = tempVal Then
match = True
End If
Next sRow
If match = False Then
Sheets("Sheet1").Cells(lRow, "Q") = "NO MATCH"
End If
Next lRow
End Sub
I have also used:
With Application
.AskToUpdateLinks = False
.ScreenUpdating = False
.DisplayAlerts = False
.EnableEvents = False
End With
To make sure nothing stands in the way.
Please Help!
This will loop through rows to match column A on Sheet1 with column K on sheet2. On a non-match "No Match" will be put in Sheet1 column Q.
On a match Sheet2 columns O,P and Q will be copied to Sheet1 columns O,P and Q.
This took about 10 seconds to run for over 12k in column A and over 2500 in column K.
Sub match_columns()
Dim I, total, fRow As Integer
Dim found As Range
total = Sheets(1).Range("A" & Rows.Count).End(xlUp).Row
For I = 1 To total
answer1 = Worksheets(1).Range("A" & I).Value
Set found = Sheets(2).Columns("K:K").Find(what:=answer1) 'finds a match
If found Is Nothing Then
Worksheets(1).Range("Q" & I).Value = "NO MATCH"
Else
fRow = Sheets(2).Columns("K:K").Find(what:=answer1).Row
Worksheets(1).Range("O" & I).Value = Worksheets(2).Range("O" & fRow).Value
Worksheets(1).Range("P" & I).Value = Worksheets(2).Range("P" & fRow).Value
Worksheets(1).Range("Q" & I).Value = Worksheets(2).Range("Q" & fRow).Value
End If
Next I
End Sub
Thank you again #Mooseman for providing the solution!
I only had to change Range A with K, at first even so I was not able to make it work as it copied only the first line. I already had some code which opened the Worksheets and copied them to a new Worksheet/added new columns ..etc., to be SavedAs for later use, and it seems that because of this your code was not able to loop properly (not sure how to explain this) in any case at the end of the open / save workbooks ..etc I have introduced a Call Sub Procedure which worked like a charm!
Also, introduced two extra lines to properly format columns O and P as Date.
I am sure it could have looked better than this, but so far it works!
And thank you to everyone who provided me with suggestions, there is still a lot to learn and I am planning to test other ways just for the sake of learning, but I needed this to work now.
Sub Button1_Click()
With Application
.AskToUpdateLinks = False
.ScreenUpdating = False
.DisplayAlerts = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
'Code to Open / Save / introduce new columns into Sheet(1)
Call match_columns
End Sub
Sub match_columns()
Dim I, total, frow As Integer
Dim found As Range
total = Sheets(1).Range("K" & Rows.Count).End(xlUp).Row
'MsgBox (total) --> used to test if it can count/see the total number of rows
For I = 2 To total
answer1 = Worksheets(1).Range("K" & I).Value
Set found = Sheets(2).Columns("A:A").Find(what:=answer1) 'finds a match
If found Is Nothing Then
Worksheets(1).Range("Q" & I).Value = "NO MATCH"
Else
frow = Sheets(2).Columns("A:A").Find(what:=answer1).Row
Worksheets(1).Range("O" & I).Value = Worksheets(2).Range("O" & frow).Value
Worksheets(1).Range("P" & I).Value = Worksheets(2).Range("P" & frow).Value
Worksheets(1).Range("Q" & I).Value = Worksheets(2).Range("Q" & frow).Value
End If
Next I
Worksheets(1).Range("P2", "P" & total).NumberFormat = "dd.mm.yyyy"
Worksheets(1).Range("O2", "O" & total).NumberFormat = "dd.mm.yyyy"
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.EnableEvents = True
.AskToUpdateLinks = True
.Calculation = xlCalculationAutomatic
End With
End Sub
This is slow because your macro is iterating through 55,000 * 2,500 rows of data, twice. That's 275,000,000 cycles.
I think the solution is to scrap the macro and use VLOOKUP or Index Match.
You could add this formula to cell Q2 of sheet1:
=IFERROR(INDEX(Sheet2!$Q:$Q,MATCH(Sheet1!$K2,Sheet2!$A:$A,0)),"NO MATCH")
That is how I would do this. If you need it to be a macro, you can write a macro that just sets Sheet1 K2 to have this formula and drag the formula down.