Iterating through a column, creating new worksheet based on cell VBA - excel

Want to iterate through column first checking if name in the excel exists as a worksheet, if not then create a worksheet with that name, but existing code does not work.
Sub genWorksheet()
' for loop to iterate through column b
' get name from column b and store name n variable
' checks if a worksheet with the name in the cell exists
' if not, then it will create a new worksheet
Dim myRow As Integer
Dim categoryName As String
Dim sht As Worksheet
Dim shtName As String
Dim found As Boolean
myRow = 4
Do While Cells(myRow, 1) <> ""
myRow = myRow + 1
categoryName = Range("B" & myRow) 'Set variable equal to the category name
For Each sht In ThisWorkbook.Worksheets 'For each sheet in the workbook
found = False ' set found = false
If sht.name = categoryName Then ' check if the sheet name equals too category name
found = True ' if it does then set found equal to true
End If
If found = True Then ' break out of the loop since we did find a match
Exit For
End If
Next sht
If found = False Then ' if no match was foundthen add the new sheet
Sheets.Add.name = categoryName
End If
Loop
End Sub
Here is the excel data if needed:
Picture of the excel data

There are two issues with your code.
Firstly, you increment MyRow immediately after testing, not at the end of the iteration. The increment needs to go at the end of your loop.
Secondly, you haven't specified in your code which worksheet column B is on. This is probably fine when you start the loop, but once a worksheet is found to be missing, it creates the worksheet and thereafter starts looking at that worksheets column B - which will be empty and cause the loop to stop.
I have a shorter way to test if a worksheet exists - which removes the need for the inner loop. Here is my revised version of your code which I believe will suit your purposes:
Sub genWorksheet()
' for loop to iterate through column b
' get name from column b and store name n variable
' checks if a worksheet with the name in the cell exists
' if not, then it will create a new worksheet
Dim myRow As Long
Dim categoryName As String
With ActiveSheet ' or specify the name with: Worksheets("sheetname")
myRow = 4
Do While .Cells(myRow, 1) <> ""
categoryName = .Range("B" & myRow) 'Set variable equal to the category name
If Evaluate("ISREF('" & categoryName & "'!A1)") = False Then ' if no match was foundthen add the new sheet
Sheets.Add.Name = categoryName
End If
myRow = myRow + 1
Loop
End With
End Sub
I note that you're getting the sheet name from column B, but you're testing column A to ensure you've not reached the end of your list. Is that your intention? If not, change Do While .Cells(myRow, 1).. to Do While .Cells(myRow, 2).. to perform your test on column B

Related

Add sheets and rename in loop

I have a "template" sheet that I copy in a loop (number of values in a column in another sheet) and then I use that value in the column to rename the sheet.
I unhide the template sheet, copy after, and then rename the sheet using the Index plus the loop index i.
This approach is dependent on the template sheet always being in the same location, so the other sheets can be inserted after and the index is correct.
I'd like, on each iteration of the loop, the copied sheet added as the last sheet and then renamed, so that it is not dependent on the "template" index value (in case a user inserts a sheet after the "template").
Sub AddMultipleSheet2()
Dim sheets_count As Integer
Dim sheet_name As String
Dim i As Integer
Worksheets("Template").Visible = True
sheet_count = Range("B12:B61").Rows.Count
For i = 1 To sheet_count
sheet_name = Sheets("Test setup").Range("B12:B61").Cells(i, 1).Value
If SheetCheck(sheet_name) = False And sheet_name <> "" Then
'Copy sheet
Set ws = Sheets("FAR 1")
ws.Copy After:=Sheets(Sheets.Count)
'Rename sheet (name of test step)
Set wsNew = Sheets(Sheets("Template").Index + i)
wsNew.Name = sheet_name
'Set value in new sheet
Set myCellSetValue = ThisWorkbook.Worksheets(sheet_name).Range("A1")
'set cell value with Range.Value property
myCellSetValue.Value = sheet_name
End If
Next i
Worksheets("Template").Visible = False
End Sub
You put the copy after the last sheet, so you can pick it up from there:
Set wsNew = Sheets(Sheets.Count)

How to find the differences in column A in 4 different worksheets

I have column K in "filter" sheets that need to be compare with column A in "Active_Buy", "Active_Others" and "Active_Make" sheets accordingly.
First it need to be compare with active_buy sheets. if there is value that in column K (filter sheet) but not in column A (active_Buy sheet), then it need to hold that value and compare it with column A (active_others sheets). If also didnt match, it need to compared with column A (Active_Make sheets).
So, if there is no any match, then the value need to be paste in new sheets name (Unmatched Part No).
I already search everywhere but only can find code that can only compare 2 worksheets only but not more than that.
'Below is the code that i found but only compared two worksheets only
' the concept just same like this but need to hold unmatch value and compare to next worksheet and so on.
Sub compare()
Sheets(3).Activate 'Go to sheet 3
Cells.Clear 'and clear all previous results
Range("a1").Select 'set cursor at the top
Sheets(1).Activate 'go to sheet 1
Range("a1").Select 'begin at the top
Dim search_for As String 'temp variable to hold what we need to look for
Dim cnt As Integer 'optional counter to find out how many rows we found
Do While ActiveCell.Value <> "" 'repeat the follwoing loop until it reaches a blank row
search_for = ActiveCell.Offset(0, 1).Value 'get a hold of the value in column B
Sheets(2).Activate 'go to sheet(2)
On Error Resume Next 'incase what we search for is not found, no errors will stop the macro
Range("b:b").Find(search_for).Select 'find the value in column B of sheet 2
If Err <> 0 Then 'If the value was not found, Err will not be zero
On Error GoTo 0 'clearing the error code
Sheets(1).Activate 'go back to sheet 1
r = ActiveCell.Row 'get a hold of current row index
Range(r & ":" & r).Select 'select the whole row
cnt = cnt + 1 'increment the counter
Selection.Copy 'copy current selection
Sheets(3).Activate 'go to sheet 3
ActiveCell.PasteSpecial xlPasteAll 'Past the entire row to sheet 3
ActiveCell.Offset(1, 0).Select 'go down one row to prepare for next row.
End If
Sheets(1).Activate 'return to sheet 1
ActiveCell.Offset(1, 0).Select 'go to the next row
Loop 'repeat
Sheets(3).Activate 'go to sheet 3 to examine findings
MsgBox "I have found " & cnt & " rows that did not exist in sheet 2"
End Sub
I'd use a For Each loop to run through the values on the 'Filter' sheet, set ranges on each of the other sheets, then check in each of the ranges. I've tested this code and it seems to do the trick. I've commented so you can see what's going on at each line.
(You'll need to adjust the sheet names to match you own, and adjust Application settings to make things run faster if you've got a lot of data.)
Sub compareColumns()
Dim lastRow1, lastRowAB, lastRowAO, lastRowAM, lastRowUMPN As Long
Dim rng1, rngAB, rngAO, rngAM As Range
Dim cell As Range
Dim found As Range
' Define our last rows for each sheet
lastRow1 = ThisWorkbook.Worksheets("FilterSheet").Range("K" & Rows.Count).End(xlUp).Row
lastRowAB = ThisWorkbook.Worksheets("ActiveBuy").Range("A" & Rows.Count).End(xlUp).Row
lastRowAO = ThisWorkbook.Worksheets("ActiveOthers").Range("A" & Rows.Count).End(xlUp).Row
lastRowAM = ThisWorkbook.Worksheets("ActiveMake").Range("A" & Rows.Count).End(xlUp).Row
lastRowUMPN = ThisWorkbook.Worksheets("UnmatchedPartNo").Range("A" & Rows.Count).End(xlUp).Row
' Set the ranges that we'll loop through
Set rng1 = ThisWorkbook.Worksheets("FilterSheet").Range("K1:K" & lastRow1)
Set rngAB = ThisWorkbook.Worksheets("ActiveBuy").Range("A1:A" & lastRowAB)
Set rngAO = ThisWorkbook.Worksheets("ActiveOthers").Range("A1:A" & lastRowAO)
Set rngAM = ThisWorkbook.Worksheets("ActiveMake").Range("A1:A" & lastRowAM)
' Loop through each cell in the filtered sheet
For Each cell In rng1
' Try to find the value in ActiveBuy sheet
Set found = rngAB.Find(cell.Value)
' If not found, try the next sheet
If found Is Nothing Then
Set found = rngAO.Find(cell.Value)
' If not found, try the next sheet
If found Is Nothing Then
Set found = rngAM.Find(cell.Value)
' If still not found, copy to the value to the 'Unmatched Parts' sheet
If found Is Nothing Then
ThisWorkbook.Worksheets("UnmatchedPartNo").Range("A" & lastRowUMPN + 1).Value = cell.Value
MsgBox "I have found a value " & cell.Value & " that did not exist in any sheets."
End If
End If
End If
' Reset 'found' to equal nothing for the next loop
Set found = Nothing
Next
End Sub
Here's a sub that takes 2 parameters;
A cell that has the value to search for, and a number indicating the sheet to search in.
When the sub doesn't find the value in neither of the sheets, it adds a new sheet "Unmatched Part No" if it doesn't exist and adds the value that's not found in column A in that sheet:
Sub searchSheet(ByVal searchFor As Range, sheetNum As Integer)
Dim sheetsArr As Variant
sheetsArr = Array("Active_Buy", "Active_Others", "Active_Make", "Unmatched Part No") 'You can change the names of your sheets here
If sheetNum = 3 Then 'When we reach the last sheet in our array, then we haven't find a match in neither of the previous sheets
Dim ws As Worksheet, wsExist As Boolean, lastRow As Integer
wsExist = False
'Check if the sheet "Unmatched Part No" exists
For Each ws In Worksheets
If ws.Name = sheetsArr(3) Then
wsExist = True
Exit For
End If
Next ws
'If the sheet "Unmatched Part No" doesn't exist add one with this name
If Not (wsExist) Then ThisWorkbook.Sheets.Add(after:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)).Name = sheetsArr(3)
lastRow = ThisWorkbook.Sheets(sheetsArr(3)).Cells(Rows.Count, "A").End(xlUp).Row 'last used row in column A in the unmatched sheet
ThisWorkbook.Sheets(sheetsArr(3)).Range("A" & lastRow + 1).Value2 = searchFor.Value2 'append the unfound value in column A
'MsgBox "New value" & searchFor.Value2 & "appended to 'Unmatched Part No' A" & lastRow + 1
Exit Sub
End If
Dim search 'Search should be of a variant type to accept errors given by the match function
search = Application.Match(searchFor.Value2, ThisWorkbook.Sheets(sheetsArr(sheetNum)).Range("A:A"), 0)
If IsError(search) Then searchSheet searchFor, sheetNum + 1 'When match doesn't find the searchFor value, Search is an #N/A error, then search in the next sheet
End Sub
And you need another sub to call the first one passing each cell of column K of filter sheet to the first sub. Here it is:
Sub lookInSheets()
Dim lastRw As Integer, ctrlCol As Range
lastRw = ThisWorkbook.Sheets("filter").Cells(Rows.Count, "K").End(xlUp).Row 'To abbreviate the search to just the filled cells in column K
Set ctrlCol = ThisWorkbook.Sheets("filter").Range("K1:K" & lastRw)
For Each ctrlCell In ctrlCol
searchSheet ctrlCell, 0
Next ctrlCell
End Sub
Copy both subs in a new module and run the second one to achieve your goal.

Excel VBA code to copy rows to relevant named sheets not working

I have found this code on this site from a previously answered question from two years ago.
The code looks at the rows of data on a Master Sheet and copies the relevant rows based on column D (Project) to the named sheet.
If a named sheet does not exist, a comment box is added to Column D, stating that the sheet name does not exist.
The code also looks at Column A (Invoice) and uses this a a unique ID so duplicate rows are not copied to the named sheets.
I amended the code to suit my needs (sheet titles, etc) but when I run the code, the relevant row is NOT copied to the named sheet but to the next sheet to the right.
I can't work out what is wrong with the code. Hoping someone can help!!!
Column A Column B Column C Column D
Invoice Date Amount Project
I18-1234 1/10/2018 $125.00 Project 1
I18-5678 10/10/2018 $1,500.00 Project 2
I18-2468 20/10/2018 $10,000.00 Project 1
I18-7931 15/10/2018 $300.00 Project 3
I18-1010 24/10/2018 $1,000.00 Project 1
I have a main sheet named "Master Sheet". This is where all data is entered.
Currently, I have another sheet named "Project 1".
The other sheets I have are named "Sheet2" and "Sheet3". (This is just while I test the code).
Sub Test()
Dim cell As Range
Dim cmt As Comment
Dim bolFound As Boolean
Dim sheetNames() As String
Dim lngItem As Long, lngLastRow As Long
Dim sht As Worksheet, shtMaster As Worksheet
Dim MatchRow As Variant
'Set master sheet
Set shtMaster = ThisWorkbook.Worksheets("Master Data")
'Get the names for all other sheets
ReDim sheetNames(0)
For Each sht In ThisWorkbook.Worksheets
If sht.Name <> shtMaster.Name Then
sheetNames(UBound(sheetNames)) = sht.Name
ReDim Preserve sheetNames(UBound(sheetNames) + 1)
End If
Next sht
ReDim Preserve sheetNames(UBound(sheetNames) - 1)
For Each cell In shtMaster.Range("D2:D" & shtMaster.Cells(shtMaster.Rows.Count, "D").End(xlUp).Row)
bolFound = False
' instead of looping through the array of sheets >> use Application.Match
If Not IsError(Application.Match(cell.Value2, sheetNames, 0)) Then
bolFound = True
Set sht = ThisWorkbook.Worksheets(sheetNames(Application.Match(cell.Value2, sheetNames, 0)))
' now use a 2nd Match, to find matches in Unique column "A"
MatchRow = Application.Match(cell.Offset(, -3).Value, sht.Range("A:A"), 0)
If Not IsError(MatchRow) Then
shtMaster.Rows(cell.Row).EntireRow.Copy Destination:=sht.Cells(MatchRow, 1)
Else '<-- no match in sheet, add the record at the end
On Error GoTo SetFirst
lngLastRow = sht.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row + 1
On Error GoTo 0
shtMaster.Rows(cell.Row).EntireRow.Copy Destination:=sht.Cells(lngLastRow, 1)
End If
End If
If bolFound = False Then
For Each cmt In shtMaster.Comments
If cmt.Parent.Address = cell.Address Then cmt.Delete
Next cmt
cell.AddComment "no sheet found for this row"
ActiveSheet.EnableCalculation = False
ActiveSheet.EnableCalculation = True
End If
Set sht = Nothing
Next
Exit Sub
SetFirst:
lngLastRow = 1
Resume Next
End Sub
change your part of the code :
' instead of looping through the array of sheets >> use Application.Match
If Not IsError(Application.Match(cell.Value2, sheetNames, 0)) Then
bolFound = True
Set sht = ThisWorkbook.Worksheets(sheetNames(Application.Match(cell.Value2, sheetNames, 0)))
to
' instead of looping through the array of sheets >> use Application.Match
If Not IsError(Application.Match(cell.Value2, sheetNames, 0)) Then
bolFound = True
Set sht = ThisWorkbook.Worksheets(cell.Value)

Need VB code that will merge two sheets into a new sheet

I am new to VB, and need some help. I have an excel 2013 workbook that has 2 sheets. Sheet1 is list of employee names (column A has 20 names), dob (column B), etc, and Sheet2 is a blank evaluation form. I need a code that will copy the entire Sheet2 (the blank form) and paste into a new Sheet3, and also pull the EmpName from row1 to a specified cell on Sheet3 (D4), same with DOB (J4), etc. I need it to repeat this process for every name on Sheet1. End goal is to have a workbook that contains 20 sheets, one for each employee, in the form of an evaluation. It would also be terrific if this code could name the tab the employee name. Is this possible? I've searched online extensively, and cannot find anything fitting.
Here is my current code. Like I said, I'm a VBA newbie. The code creates new sheets from the employee list, and copies data, but now I need it to also copy the entire sheet2 (eval form), and place the data (name cell A1 from employee list) into the form on sheet3 (new sheet) in cell D4.
Sub CreateSheetsFromEmployeeList()
Dim nameSource
Dim nameColumn
Dim nameStartRow As Long
Dim nameEndRow As Long
Dim employeeName As String
Dim newSheet As Worksheet
nameSource = "Ayre"
nameColumn = "A"
nameStartRow = 2
nameEndRow = Worksheets(nameSource).Cells(Rows.Count, nameColumn).End(xlUp).Row
Do While (nameStartRow <= nameEndRow)
employeeName = Sheets(nameSource).Cells(nameStartRow, nameColumn)
employeeName = Trim(employeeName)
If (employeeName <> vbNullString) Then
On Error Resume Next 'do not throw error
Err.Clear 'clear any existing error
Sheets(employeeName).Name = employeeName
If (Err.Number > 0) Then
Err.Clear
On Error GoTo -1
Set newSheet = Sheets.Add(After:=Sheets(Sheets.Count))
newSheet.Name = employeeName
Sheets(nameSource).Activate
LastCol = ActiveSheet.Cells(nameStartRow, Application.Columns.Count).End(xlToLeft).Column
Range(Cells(nameStartRow, 1), Cells(nameStartRow, LastCol)).Select
Selection.Copy
Sheets(employeeName).Activate 'NEW
Sheets(employeeName).Cells(1, "A").PasteSpecial
[a1].Select 'NEW
Application.CutCopyMode = False
Sheets(employeeName).Columns("A:K").AutoFit
End If
End If
nameStartRow = nameStartRow + 1
Loop
End Sub
Record a macro
When you record a macro, the macro recorder records all the steps required to complete the actions that you want your macro to perform. Iterate your action once, stop recording, then view the macro to repeat and build out your final automation macro.
This code demonstrates the basic principles you need:
Sub ExampleForAngel()
Dim names As Worksheet
Set names = Worksheets("Sheet1")
Dim eval As Worksheet
Set eval = Worksheets("Sheet2")
Dim index As Long
index = 0
Dim name As String
While (names.Range("A1").Offset(index, 0).Value <> "")
name = names.Range("A1").Offset(index, 0)
eval.Copy after:=Worksheets(Worksheets.Count)
ActiveSheet.name = name
ActiveSheet.Range("A2").Value = name
index = index + 1
Wend
End Sub

How to Search Specific Column In Each Worksheet of Excel

I have an excel document with over 50 worksheets all with a similar naming convention.
As this will be so unfriendly for users to navigate to, I wrote a VBA macro which creates a worksheet called summary with the list of all the worksheets hyperlinked in a tabular form with Sheet A B and C as the Column and Sheet 1 and 2 as rows.
Now I am trying to go through each row of a specific column in Sheet 1 and Sheet 2 and look for any reference to SheetB, SheetC and SheetD and for each reference found and I want to mark that creating a matrix.
I am not sure how to achieve this. Any assistance will be much appreciated.
I have managed to search Sheet 1 and 2 for any reference to SheetB as shown below but I am not sure how to update the corresponding cell in my summary sheet.
Function findWord(word As String, wSheet As String) As Boolean
Dim LastRow As Long
Dim i As Long
LastRow = Worksheets(wSheet).Cells(Rows.Count, "D").End(xlUp).Row
For i = LastRow To 1 Step -1
If Worksheets(wSheet).Range("D" & i).Value = word Then
findWord = True
Exit Function
End If
Next i
End Function
For Each wsSheet In wbBook.Worksheets
If (wsSheet.Name <> wsActive.Name) And (Left(wsSheet.Name, 4) <> "fact") Then
For i = 2 To lastColumn
MsgBox wsSheet.Name
If findWord(columnNames(counter2), wsSheet.Name) Then
'Update summary sheet
End If
counter = counter2 + 1
Next i
End If
Next wsSheet
If the result in "Summary sheet" you are looking for is similar to this :
Then you can use something like this (read the comments inside the code for explanations)
Sub MarkReferencesToSheets()
Dim wsSummary As Worksheet 'sheet with summary table matrix
Dim wsSheetRow As Worksheet 'sheets in which we will search references to other sheets
Dim strSheetColumnName As String 'name of the reference we are looking for
Dim intSheetRow As Integer 'for loop purposes
Dim intSheetColumn As Integer 'for loop purposes
Set wsSummary = Sheets("Summary")
For intSheetRow = 2 To 3 'change to suit; headers for rows in summary sheet
Set wsSheetRow = Worksheets(wsSummary.Cells(intSheetRow, 1).Value)
For intSheetColumn = 2 To 4 'change to suit; headers for columns in summary sheet
strSheetColumnName = wsSummary.Cells(1, intSheetColumn) 'name of sheet we are looking for
If Not wsSheetRow.Columns(4).Find(strSheetColumnName) Is Nothing Then 'look only in column "D", or 4
wsSummary.Cells(intSheetRow, intSheetColumn) = "X" ' if we found it, mark it
Else
'if you want something else in the cell when reference is not found, put it here
End If
Next intSheetColumn
Next intSheetRow
End Sub

Resources