I have an excel workbook that have a subset of sheets with similar names: Data(US), Data(UK), Data(FR), Data(ES), etc... (in brackets there is the ISO code of the country which data refer to).
I would like to extract two data-points from all these sheets, and print them as a list in a new sheet to create a report.
Each sheet has the same structure inside (see here an image:
so that all the data-points are identified by coordinates for rows ("001","002", ... in row 6) and columns ("001", "002" in column D).
I am trying to write a code that does the following:
Open all sheets that have the name like: Data(**)
Inside the sheet, do a VLOOKUP to get the value corresponding to rows "001" and "002"
Print the data-points extracted in a new sheet, one after the other as a list in column D
Here is the code I wrote so far, which works only for the first sheet (Data(US)) and I included my questions as comments:
Sub ImportDataPoints()
Dim W As Worksheet, C&, F$
Dim D As String
'Take the folder path from cell D1
D = Worksheets("Input").Range("D1").Value
On Error Resume Next
'Target sheet to paste the data
Set W = ThisWorkbook.Worksheets("Data")
C = 3
Application.ScreenUpdating = False
'Open all workbooks in the folder that contain the following
F = Dir(D & "*FINANCIALDATA*" & "*.xlsx")
Do Until F = ""
C = C + 1
'Open the worksheet "Data(US)"
'### QUESTION: How to open all worksheets with similar names like Data(**)? ###
With Workbooks.Open(D & F).Worksheets("Data(US)")
'First datapoint to extract. Initial position: cell AA10.
'Do a VLOOKUP to search the value corresponding to coordinate "001"
.Range("AA10").FormulaR1C1 = "=VLOOKUP(""001"",C[-23]:C[-1],2,FALSE)"
'Move to AB10: if the previous value is empty, then give me zero
.Range("AB10").FormulaR1C1 = "=IF(RC[-1]="""",0,RC[-1])"
'Copy the value
.Range("AB10").Copy
'Paste the value in the Target sheet at row 10, column D
W.Cells(10, C).PasteSpecial xlPasteValues
'Do the same for the second datapoint and paste it in the Target sheet at row 11, column D
.Range("AA10").Offset(1, 0).FormulaR1C1 = "=VLOOKUP(""002"",C[-23]:C[-1],2,FALSE)"
.Range("AB10").Offset(1, 0).FormulaR1C1 = "=IF(RC[-1]="""",0,RC[-1])"
.Range("AB10").Offset(1, 0).Copy
W.Cells(11, C).PasteSpecial xlPasteValues
'### QUESTION: The macro should continue opening all the other sheets (Data(UK), Data(FR), Data(ES), etc...),
'### copying the datapoints 001-002 and pasting them in the same target sheet (column D, continuing from the row 11 onwards...)###
.Parent.Close False
End With
F = Dir
Loop
Set W = Nothing
Application.ScreenUpdating = True
End Sub
Does anybody know how to fix the code? Or if you can think to any other more efficient solution, all proposal are well accepted!
Many thanks in advance!
Something like this:
Sub ImportDataPoints()
Dim W As Worksheet, C&, F$
Dim D As String, wb As Workbook, targetRow As Long, sht As Worksheet
'Take the folder path from cell D1
D = Worksheets("Input").Range("D1").Value
'Target sheet to paste the data
Set W = ThisWorkbook.Worksheets("Data")
C = 3
Application.ScreenUpdating = False
'Open all workbooks in the folder that contain the following
F = Dir(D & "*FINANCIALDATA*.xlsx")
Do Until F = ""
C = C + 1
Set wb = Workbooks.Open(D & F)
targetRow = 10 'summary start row
For each sht in wb.worksheets
If sht.Name Like "Data(*)" Then
'....
'run your code for sheet sht
'....
targetRow = targetRow + 2 'next summary row
End With
Next sht
wb.close True
F = Dir
Loop
Set W = Nothing
Application.ScreenUpdating = True
End Sub
Related
I hope you are all well.
Please may I ask a question:
I'm using this youtuber's csv as an example:example csv
I'd like to move all the lines with duplicated names into another csv file. Is there a way to do this with a particular excel formula?
Therefore, my aim would be to have the first Mariya, Andrew and nancy rows in this csv and move all the duplicates into another one. Then in that 2nd csv do the same thing so that I end up with a few csv files each with the row data for each name only appearing once (so 1001, 1003, 1008... will be in the 1st csv; 1002, 1004, 1014... will be in the 2nd csv and so on).
I have so far consolidated my csv data into one file using the cmd prompt.
update: this is my current VBA script:
'VBA Codeto movethe entire row if cells in column 4 has the value Duplicate
Sub move_rows_to_another_sheet()
For Each myCell In Selection.Columns(4).Cells
If myCell.Value = "Duplicate" Then
myCell.EntireRow.Copy Sheet2.Range("A" & Rows.Count).End(3)(2)
myCell.EntireRow.Delete
End If
Next
End Sub
I've added my excel sheet 1 as an image here: sheet 1.
I want my code to put all the duplicate rows into sheet 2. Then run the same code in sheet 2 and create a new sheet automatically, and continue doing this until i have several sheets without any duplicates in the specified column (Co Name).
The function: =IF(COUNTIF($A$2:$A5,A5)>1, "Duplicate","") works intermittently. The function ignores the first occurrence. However, it sometimes misses out duplicates.
I will update here on my progress but any help would be greatly appreciated :)
Kind regards,
Yogi
If I understand you correctly:
Sub test()
Dim rg As Range: Dim rgHdr As Range: Dim cell As Range
Dim arr: Dim el: Dim cnt As Long: Dim nm As Range
'delete certain sheets if exist
Application.DisplayAlerts = False
For Each sh In Sheets
If InStr(sh.Name, "result") Then sh.Delete
Next
Application.DisplayAlerts = True
'csv file has only one sheet, so it's the active sheet
'set the range of the name (column D) as rg variable on the active sheet
With ActiveSheet
Set rg = .Range("D2", .Range("D" & Rows.Count).End(xlUp))
Set rgHdr = .Range("A1", .Range("A1").End(xlToRight))
End With
'get each unique name in rg as arr variable
Set arr = CreateObject("scripting.dictionary")
For Each cell In rg: arr.Item(cell.Value) = 1: Next
'loop to each item (the unique name) in arr as el variable to get the most occurence of the name
'then have the count value as cnt variable
'for example, if under column D (SalesPerson) Sales X appear for 6 times while all other sales < 6
'then it means the total sheet needed is 6 sheets where the 6th sheet will only has this Sales X and his data
cnt = 0
For Each el In arr
If Application.CountIf(rg, el) > cnt Then cnt = Application.CountIf(rg, el): nm = el
Next
'create new sheets as many as the cnt value and put the rgHdr value
For i = 1 To cnt
Sheets.Add.Name = "result_" & Format(i, "00")
Range("A1").Resize(1, rgHdr.Columns.Count).Value = rgHdr.Value
Next i
'again, loop to each item in arr as el variable
'this time is to get the range of cells which value = the looped el (the name) as nm variable
For Each el In arr
With rg
.Replace el, True, xlWhole, , False, , False, False
Set nm = .SpecialCells(xlConstants, xlLogical) '.EntireRow.Delete
.Replace True, el, xlWhole, , False, , False, False
End With
'now the nm variable has the range of cells of the looped name
'next is to loop to each cell of nm variable and copy each looped cell row to the designated sheet
i = 1
For Each cell In nm
cell.EntireRow.Copy Destination:=Sheets("result_" & Format(i, "00")).Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
i = i + 1
Next
Next
End Sub
FYI, the sub does not create a new csv file, but put the result in created sheet.
If in each created sheet result is the one that you expected but then you want that each created sheet is saved as csv file, then it need additional code.
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 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)
I currently have a master excel sheet that has the names of about 20 different sales people, and a new row is created, with the salesmen name in column A, whenever they make a sale. But, I now want this data to be available to the salesmen, but I want only them to only be able to view their info, not everyones. So, I am going to create 20 different individual files, one for each salesman.
Is there a formula that I can use for these 20 different spreadsheets to update for that specific salesmen every time I update the master sheet?
You could create workbooks from a Column (Looping from row 1 to x) based on unique values.
So for each unique salesmen in Column A you create a new workbook. Then you only need to use your current Master file, and do whatever you want in that file. When you want to send a sheet to a sales person, you execute the code and Excel will copy all rows that belongs to the specific sales man and create 20 individual sheets for you which you can send.
Process:
I have a file in a folder, which I have all my main data.
The main data looks like this, and the new workbooks will be named after Column A. It will only create workbook for unique names.
After running the macro it has create the following 5 new workbooks.
This is how Workbook "Anne - 10-27-18,14.24.47.xlsx" looks like:
This is how Workbook "Belle- 10-27-18,14.24.47.xlsx" looks like:
I used the following code and only modified to make it dynamic of the unique list column. All credit to J. Fox at SO
VBA Code:
Option Explicit
Sub ExportByName()
'Source and Credit: https://stackoverflow.com/questions/46368771/how-to-create-a-new-workbook-for-each-unique-value-in-a-column
Dim unique(1000) As String 'How many unique values we can store
Dim wb(1000) As Workbook
Dim ws As Worksheet
Dim x As Long, y As Long, ct As Long, uCol As Long, ColName As Long
Dim StaticDate As Date
On Error GoTo ErrHandler
Application.ScreenUpdating = True
Application.Calculation = xlCalculationManual
'Your main worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1")
'Column Where Unique Names are
ColName = 1
uCol = 12 'End column of data in MainFile
ct = 0
'get a unique list of users
For x = 2 To ws.Cells(ws.Rows.Count, ColName).End(xlUp).Row
If CountIfArray(ActiveSheet.Cells(x, ColName), unique()) = 0 Then
unique(ct) = ActiveSheet.Cells(x, ColName).Text
ct = ct + 1
End If
Next x
StaticDate = Now() 'This create the same timestamp for all the new workbooks
'loop through the unique list
For x = 0 To ws.Cells(ws.Rows.Count, ColName).End(xlUp).Row - 1
If unique(x) <> "" Then
'add workbook
Set wb(x) = Workbooks.Add
'copy header row
ws.Range(ws.Cells(1, 1), ws.Cells(1, uCol)).Copy wb(x).Sheets(1).Cells(1, 1)
'loop to find matching items in ws and copy over
For y = 2 To ws.Cells(ws.Rows.Count, ColName).End(xlUp).Row
If ws.Cells(y, ColName) = unique(x) Then
'copy full formula over
'ws.Range(ws.Cells(y, 1), ws.Cells(y, uCol)).Copy wb(x).Sheets(1).Cells(WorksheetFunction.CountA(wb(x).Sheets(1).Columns(uCol)) + 1, 1)
'to copy and paste values
ws.Range(ws.Cells(y, 1), ws.Cells(y, uCol)).Copy
wb(x).Sheets(1).Cells(WorksheetFunction.CountA(wb(x).Sheets(1).Columns(uCol)) + 1, 1).PasteSpecial (xlPasteValues)
End If
Next y
'autofit
wb(x).Sheets(1).Columns.AutoFit
'save when done
wb(x).SaveAs ThisWorkbook.Path & "\" & unique(x) & " - " & Format(StaticDate, "mm-dd-yy, hh.mm.ss") & ".xlsx"
wb(x).Close SaveChanges:=True
Else
'once reaching blank parts of the array, quit loop
Exit For
End If
Next x
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
ErrHandler:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Public Function CountIfArray(lookup_value As String, lookup_array As Variant)
CountIfArray = Application.Count(Application.Match(lookup_value, lookup_array, 0))
End Function
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