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
Related
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
The goal is to use a reference Excel workbook as a database to find matching BoxID and then copy cells D to G in the same row. Finally pasting to another workbook that consists of a single worksheet.
I figured Xlookup would be easiest. In Excel it works but it doesn't in VBA.
Three main questions
How do I open another workbook and then reference all sheets or a specific range through all sheets in a dynamically named workbook to my current activeworkbook?
(e.g. sheets will be named freezer 23, freezer 43, fridge 190 in database.)
The rows of the sheets is variable but the columns stay the same.
Is there a way to do the above but if nothing is found to leave the cell blank?
Is there a way I could simplify this code?
On the left is the database which is going to be the external reference/where the data is coming from and on the right is the output sheet. Where I will be using Xlookup to search for the matching value. column "A" is where the search value will be and output to the next 4 cells.
Sub FreezerPulls()
Dim lastrow, j As Long
lastrow = Cells(Rows.Count, 1).End(xlUp).Row
Dim a As Integer
Dim list As Workbook
Dim frzdatabase As
Dim BoxIDlist, info, BoxIDdatabase, database, databasepath As String
databasepath = ("C:\Users\mikeo\Desktop\DataBaseStandard.xlsm")
Workbooks.Open ("C:\Users\mikeo\Desktop\DataBaseStandard.xlsm")
database = "DataBaseStandard.xlsm"
Set list = ThisWorkbook
list.Activate
Set BoxIDlist = Worksheets("Sheet1").Range("A" & Row.Count).End(xlUp).Row 'emphasized textthis doesn't work
Set BoxIDdatabase = Range("A2:A1500")
Set info = Range("D2:G1500")
a = Application.Worksheets.Count
End Sub
You could do something like this, using Match(). See comments in code
Sub FreezerPulls()
Const DB_PATH As String = "C:\Users\mikeo\Desktop\DataBaseStandard.xlsm"
Dim wbData As Workbook, ws As Worksheet, rw As Range, id, m
Set wbData = Workbooks.Open(DB_PATH, ReadOnly:=True) 'get a reference to the data workbook
'loop each row in the lookup table
For Each rw In ThisWorkbook.Sheets("Sheet1").Range("A17:F40").Rows
id = rw.Cells(1).Value 'Box ID to find
If Len(id) > 0 Then 'any value to look up?
For Each ws In wbData.Worksheets 'loop all worksheets in data workbook
m = Application.Match(id, ws.Columns("A"), 0) 'any match on this sheet ColA?
If Not IsError(m) Then 'no error = match was made on row m
rw.Cells(3).Value = ws.Name 'add freezer name
rw.Cells(4).Resize(1, 3).Value = _
ws.Cells(m, 5).Resize(1, 3).Value 'copy segment, rackID, position
Exit For 'done searching (assumes box id's are unique)
End If
Next ws
End If
Next rw
wbData.Close False
End Sub
I don't know how to create this section of the code. This is a template code that I've used to copy specific values from a cell from each worksheet into one master worksheet that compiles that data usually into one row.
Sub distribute()
Dim sh As Worksheet
Dim destsh As Worksheet
Dim i As Integer
Set destsh = ActiveWorkbook.Worksheets.Add
destsh.Name = "Master"
i = 1
For Each sh In ActiveWorkbook.Worksheets
***destsh.Cells(i, 1).Value = sh.Range("B7:B90").SpecialCells(xlCellTypeConstants).Select***
i = i + 1
Next
ActiveWorkbook.Worksheets("Master").Cells.EntireColumn.ColumnWidth = 30
ActiveWorkbook.Worksheets("Master").Cells.EntireRow.AutoFit
ActiveWorkbook.Worksheets("Master").UsedRange.UnMerge
ActiveWorkbook.Worksheets("Master").UsedRange.WrapText = False
End Sub
I want my code to go through each worksheet in my workbook and copy the column from the range B7:B90 and stop where there are no more values within each row of each worksheet, then moves on to the next worksheet. Some worksheets have 10 cells in one row, others have 60; in this scenario my master file would show 70 cells in column A from both worksheets. The code creates a master worksheet that compiles the worksheets row B in one column.
The section I need help with has been asterisked
Your code creates the Master sheet every time which will cause the program to fail when it tries to name the sheet in the next run. Also, in your iteration through all sheets, you are reading data from Master sheet as well which might give incorrect results. I can quickly think of below code. I have used the numerical notation for rows and cells. Also since the range is constant, i looped through the range that you specified
Sub distribute()
Dim sh As Worksheet
Dim destsh As Worksheet
Dim i As Integer: i = 1
Dim sheetName As String: sheetName = ""
Set destsh = ActiveWorkbook.Worksheets.Add
'Taking sheet name as input from user
sheetName = InputBox("Enter sheetname to aggregate data")
'Checking if sheetname was entered properly
If (sheetName <> "") Then
destsh.Name = sheetName
ActiveWorkbook.Worksheets("Master").Cells.EntireColumn.ColumnWidth = 30
ActiveWorkbook.Worksheets("Master").Cells.EntireRow.AutoFit
ActiveWorkbook.Worksheets("Master").UsedRange.UnMerge
ActiveWorkbook.Worksheets("Master").UsedRange.WrapText = False
masterSheetRow = 1
For Each sh In ActiveWorkbook.Worksheets
'Making sure that the sheet is not the master sheet while getting rows
If (sh.Name <> sheetName) Then
For i = 7 To 90
If (sh.Cells(i, 2).Value <> "") Then
destsh.Cells(masterSheetRow, 1).Value = sh.Cells(i, 2).Value
masterSheetRow = masterSheetRow + 1
End If
Next
End If
Next
Else
MsgBox ("Enter valid sheetname")
End If
End Sub
People take a survey and their responses end up in one row in an Excel spreadsheet. People take multiple surveys, so their responses are spread throughout multiple worksheets. These people have IDs they use before every survey.
I want to loop through rows in each worksheet and copy certain cells from the row with a particular person's survey responses. The assumption is the person pulling responses into one spreadsheet knows the ID.
Sub CreateSPSSFeed()
Dim StudentID As String ' (StudentID is a unique identifier)
Dim Tool As Worksheet ' (this is the worksheet I'm pulling data into)
Dim Survey1 As Worksheet ' (this is the sheet I'm pulling data from)
Dim i As Integer ' (loop counter)
Tool = ActiveWorkbook.Sheets("ToolSheet")
Survey1 = ActiveWorkbook.Sheets("Survey1Sheet")
' (This is how the loop knows what to look for)
StudentID = Worksheet("ToolSheet").Range("A2").Value
ActiveWorksheet("Survey1").Select ' (This loop start with the Survey1 sheet)
For i = 1 to Rows.Count ' (Got an overflow error here)
If Cells (i, 1).Value = StudentID Then
'!Unsure what to do here-- need the rest of the row
' with the matching StudentID copied and pasted
' to a specific row in ToolSheet, let's say starting at G7!
End If
Next i
End Sub
I researched here and haven't had a lot of luck combining loops with moving across sheets.
This one's not good, but may get you going:
Sub CreateSPSSFeed()
Dim StudentID As String '(StudentID is a unique identifier)
Dim Tool As Worksheet '(this is the worksheet I'm pulling data into)
Dim Survey1 As Worksheet '(this is the sheet I'm pulling data from)
'Dim i As Integer '(loop counter) 'You don't need to define it
Set Tool = ActiveWorkbook.Worksheets("ToolSheet") 'you'll need to use the Set command, don't ask why
Set Survey1 = ActiveWorkbook.Worksheets("Survey1Sheet")
ToolLastRow = Tool.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row 'so you won't need to loop through a million rows each time
Survey1LastRow = Survey1.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Survey1LastColumn = Survey1.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
For j = 2 To ToolLastRow 'For each student ID from A2 down on toolsheet
StudentID = Tool.Cells(j, 1).Value2 '(This is how the loop knows what to look for) 'why define it if you don't use it
'ActiveWorksheet("Survey1").Select '(This loop start with the Survey1 sheet) 'Activeworksheet -> Activeworkbook but unnecessary,see below
For i = 1 To Survey1LastRow '(Got an overflow error here) 'you won't get an overflow error anymore
If Cells(i, 1).Value2 = StudentID Then
'!Unsure what to do here--need the rest of the row with the matching StudentID copied and pasted to a specific row in ToolSheet, let's say starting at G7!
'let's put the data starting at survey1's B# to the cells starting at tool's G#
For k = 2 To Survey1LastColumn '2 refers to B, note the difference between B=2 and G=7 is 5
Tool.Cells(j, k + 5) = Survey1.Cells(i, k)
Next k
End If
Next i
Next j
End Sub
This will check rows 1:500 (can easily change to entire column or different range) in all sheets in the workbook that starts with 'Survey' and paste to the tool sheet.
Ensure you have enough space between student id's on the toolsheet to paste all possible occurrences.
The FIND method is from here: https://msdn.microsoft.com/en-us/library/office/ff839746.aspx
Sub CreateSPSSFeed()
Dim sStudentID As String
Dim shtTool As Worksheet
Dim rFoundCell As Range
Dim sFirstFound As String
Dim rPlacementCell As Range
Dim lCountInToolSheet As Long
Dim wrkSht As Worksheet
'Set references.
With ActiveWorkbook
Set shtTool = .Worksheets("ToolSheet")
sStudentID = .Worksheets("ToolSheet").Cells(2, 1).Value
End With
'Find where the required student id is in the tool sheet.
With shtTool.Range("A:A")
'Will start looking after second row (as this contains the number you're looking for).
Set rPlacementCell = .Find(sStudentID, After:=.Cells(3), LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext)
'If the Student ID doesn't appear in column A it
'will find it in cell A2 which we don't want.
If rPlacementCell.Address = .Cells(2).Address Then
'Find the last row on the sheet containing data -
'two rows below this will be the first occurence of our new Student ID.
lCountInToolSheet = .Find("*", After:=.Cells(1), SearchDirection:=xlPrevious).Row + 2
'An existing instance of the number was found, so count how many times it appears (-1 for the instance in A2)
Else
lCountInToolSheet = WorksheetFunction.CountIf(shtTool.Range("A:A"), sStudentID) - 1
End If
'This is where our data will be placed.
Set rPlacementCell = rPlacementCell.Offset(lCountInToolSheet)
End With
'Look at each sheet in the workbook.
For Each wrkSht In ActiveWorkbook.Worksheets
'Only process if the sheet name starts with 'Survey'
If Left(wrkSht.Name, 6) = "Survey" Then
'Find each occurrence of student ID in the survey sheet and paste to the next available row
'in the Tool sheet.
With wrkSht.Range("A1:A500")
Set rFoundCell = .Find(sStudentID, LookIn:=xlValues, LookAt:=xlWhole)
If Not rFoundCell Is Nothing Then
sFirstFound = rFoundCell.Address
Do
'Copy the whole row - this could be updated to look for the last column containing data.
rFoundCell.EntireRow.Copy Destination:=rPlacementCell
Set rPlacementCell = rPlacementCell.Offset(1)
Set rFoundCell = .FindNext(rFoundCell)
Loop While Not rFoundCell Is Nothing And rFoundCell.Address <> sFirstFound
End If
End With
Set rFoundCell = Nothing
End If
Next wrkSht
End Sub
Edit: I've added more comments and extra code as realised the first section would always find the Student ID that is placed in cell A2.
Try this:
Sub CreateSPSSFeed()
Dim StudentID As String '(StudentID is a unique identifier)
Dim rng as Range
StudentID = Worksheet("ToolSheet").Range("A2").Value 'if you get error try to add Set = StudentID.....
j = 7
for x = 2 to sheets.count
For i = 1 to Sheets(x).Cells(Rows.Count, 1).End(xlUp).Row 'last not empty row
If sheets(x).Cells (i, 1).Value = StudentID Then
sheets(x).range(cells(i, 2),cells(i, 6)).copy _'adapt range to your needs
Destination:=activesheet.Cells(j, 7) 'this is G7
j = j + 1
End If
Next i
next x
End Sub
Run this code only from sheet where you pooling data into "Tool".
Now you have nested loop for rows in loop for sheets.
PS: no need to copy entire row, just range with value, to avoid errors.
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