I'm attempting to write a macro to take an excel file of several thousand rows and split the inital sheet's rows up into sheets of 250 rows per-sheet, not including the original header row, which should also be copied to each sheet. There are 13 columns total, and some of the fields are empty.
I can sort the document myself - that's not an issue - I just don't have the macro skill to figure this one out.
I've tried searching, and found a few examples, but none quite fit..such as this one..
create macro that will convert excel rows from single sheet to new sheets ..or this one.. Save data input from one sheet onto successive rows in another sheet
Any help?
This should provide the solution you are looking for as well. You actually added your answer as I was typing it, but maybe someone will find it useful.
This method only requires that you enter the number of rows to copy to each page, and assumes you are on the "main" page once you execute it.
Sub AddSheets()
Application.EnableEvents = False
Dim wsMasterSheet As Excel.Worksheet
Dim wb As Excel.Workbook
Dim sheetCount As Integer
Dim rowCount As Integer
Dim rowsPerSheet As Integer
Set wsMasterSheet = ActiveSheet
Set wb = ActiveWorkbook
rowsPerSheet = 5
rowCount = Application.CountA(Sheets(1).Range("A:A"))
sheetCount = Round(rowCount / rowsPerSheet, 0)
Dim i As Integer
For i = 1 To sheetCount - 1 Step 1
With wb
'Add new sheet
.Sheets.Add after:=.Sheets(.Sheets.Count)
wsMasterSheet.Range("A1:M1").EntireRow.Copy Destination:=Sheets(.Sheets.Count).Range("A1").End(xlUp)
wsMasterSheet.Range("A" & (rowsPerSheet + 2) & ":M" & (2 * rowsPerSheet + 1)).EntireRow.Cut Destination:=Sheets(.Sheets.Count).Range("A" & Rows.Count).End(xlUp).Offset(1)
wsMasterSheet.Range("A" & (rowsPerSheet + 2) & ":M" & (2 * rowsPerSheet + 1)).EntireRow.Delete
ActiveSheet.Name = "Rows " + CStr(((.Sheets.Count - 1) * rowsPerSheet + 1)) & " - " & CStr((.Sheets.Count * rowsPerSheet))
End With
Next
wsMasterSheet.Name = "Rows 1 - " & rowsPerSheet
Application.EnableEvents = True
End Sub
#pnuts's suggested solution by Jerry Beaucaire worked perfectly.
https://sites.google.com/a/madrocketscientist.com/jerrybeaucaires-excelassistant/parse-functions/rows
Option Explicit
Sub SplitDataNrows()
'Jerry Beaucaire, 2/28/2012
'Split a data sheet by a variable number or rows per sheet, optional titles
Dim N As Long, rw As Long, LR As Long, Titles As Boolean
If MsgBox("Split the activesheet into smaller sheets?", vbYesNo, _
"Confirm") = vbNo Then Exit Sub
N = Application.InputBox("How many rows per sheet?", "N-Rows", 50, Type:=1)
If N = 0 Then Exit Sub
If MsgBox("Include the title row1 on each new sheet?", vbYesNo, _
"Titles?") = vbYes Then Titles = True
Application.ScreenUpdating = False
With ActiveSheet
LR = .Range("A" & .Rows.Count).End(xlUp).Row
For rw = 1 + ---Titles To LR Step N
Sheets.Add
If Titles Then
.Rows(1).Copy Range("A1")
.Range("A" & rw).Resize(N).EntireRow.Copy Range("A2")
Else
.Range("A" & rw).Resize(N).EntireRow.Copy Range("A1")
End If
Columns.AutoFit
Next rw
.Activate
End With
Application.ScreenUpdating = True
End Sub
--
Option Explicit
Sub SplitWorkbooksByNrows()
'Jerry Beaucaire, 2/28/2012
'Split all data sheets in a folder by a variable number or rows per sheet, optional titles
'assumes only one worksheet of data per workbook
Dim N As Long, rw As Long, LR As Long, Cnt As Long, Cols As String, Titles As Boolean
Dim srcPATH As String, destPATH As String, fNAME As String, wbDATA As Workbook, titleRNG As Range
srcPATH = "C:\Path\To\Source\Files\" 'remember the final \ in this string
destPATH = "C:\Path\To\Save\NewFiles\" 'remember the final \ in this string
'determine how many rows per sheet to create
N = Application.InputBox("How many rows per sheet?", "N-Rows", 50, Type:=1)
If N = 0 Then Exit Sub 'exit if user clicks CANCEL
'Examples of usable ranges: A:A A:Z C:E F:F
Cols = Application.InputBox("Enter the Range of columns to copy", "Columns", "A:Z", Type:=2)
If Cols = "False" Then Exit Sub 'exit if user clicks CANCEL
'prompt to repeat row1 titles on each created sheet
If MsgBox("Include the title row1 on each new sheet?", vbYesNo, _
"Titles?") = vbYes Then Titles = True
Application.ScreenUpdating = False 'speed up macro execution
Application.DisplayAlerts = False 'turn off system alert messages, use default answers
fNAME = Dir(srcPATH & "*.xlsx") 'get first filename from srcPATH
Do While Len(fNAME) > 0 'exit loop when no more files found
Set wbDATA = Workbooks.Open(srcPATH & fNAME) 'open found file
With ActiveSheet
LR = Intersect(.Range(Cols), .UsedRange).Rows.Count 'how many rows of data?
If Titles Then Set titleRNG = Intersect(.Range(Cols), .Rows(1)) 'set title range, opt.
For rw = 1 + ---Titles To LR Step N 'loop in groups of N rows
Cnt = Cnt + 1 'increment the sheet creation counter
Sheets.Add 'create the new sheet
If Titles Then titleRNG.Copy Range("A1") 'optionally add the titles
'copy N rows of data to new sheet
Intersect(.Range("A" & rw).Resize(N).EntireRow, .Range(Cols)).Copy Range("A1").Offset(Titles)
ActiveSheet.Columns.AutoFit 'cleanup
ActiveSheet.Move 'move created sheet to new workbook
'save with incremented filename in the destPATH
ActiveWorkbook.SaveAs destPATH & "Datafile_" & Format(Cnt, "00000") & ".xlsx", xlNormal
ActiveWorkbook.Close False 'close the created workbook
Next rw 'repeat with next set of rows
End With
wbDATA.Close False 'close source data workbook
fNAME = Dir 'get next filename from the srcPATH
Loop 'repeat for each found file
Application.ScreenUpdating = True 'return to normal speed
MsgBox "A total of " & Cnt & " data files were created." 'report
End Sub
Related
I am beginner for excel VBA.
I want to use VBA to loop through autofilter criteria in column G( below photo) to copy and paste to new sheet then save as new file with sequence file name.
Below is my code, i know that it can use if else to do but the code will change to very long and difficult to revise, i want to know how to change to use the loop.
Thank you very much for your help.
Dim wb As Workbook
Dim wsw As Worksheet
Dim y As Workbook
Dim lastRow, lastRow2 As Long
Dim readsheetName As String
Dim destsheetName As String
Dim fso As Object, FolDir As String, FileNm As Object, NumStr As Integer, MaxNum As Integer
Dim NewName As String, StrNum As String, MaxStr As String
Dim FolderStr As String 'Object
MaxNum = 1
FolderStr = "Q:\Alan\VBA\CCA\"
'Set fso = CreateObject("scripting.filesystemobject")
'Set FolDir = fso.GetFolder(FolderStr)
FolDir = Dir(FolderStr)
readsheetName = "2011-2019"
destsheetName = "Cable Collection Advices (2)"
Set wb = ThisWorkbook
Set wsw = wb.Sheets(readsheetName)
wsw.Activate
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Filtered Data").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Application.ScreenUpdating = False
Set wsDest = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
wsDest.Name = "Filtered Data"
MM1
wsw.Range("A1:U1").AutoFilter Field:=7, Criteria1:="296699"
wsw.Range("A1:U1").AutoFilter Field:=14, Criteria1:="Available", Operator:=xlOr, Criteria2:="="
If wsw.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
wsw.Cells.SpecialCells(xlCellTypeVisible).Copy
wsDest.Activate
wsDest.Range("A1").PasteSpecial xlPasteFormulasAndNumberFormats
wsDest.Columns("N:U").Delete
wsDest.Columns("A:B").Delete
wsDest.Columns("F").Delete
wsDest.Rows(1).Delete
lastRow = wsDest.Range("A" & Rows.Count).End(xlUp).Row
Set SourceRange = wsDest.Range("A1:D" & lastRow)
Set SourceRange2 = wsDest.Range("F1:G" & lastRow)
Set SourceRange3 = wsDest.Range("E1:E" & lastRow)
Set SourceRange4 = wsDest.Range("J1:J" & lastRow)
SourceRange.Copy
Set y = Workbooks.Open("\\SSSSNNMR20\EAS2EAS1\75 ABCDE Engineering\76 CABLE Engineering - General\PE-Test-ABCDE\E_P\02 AB\Alan\VBA\CCA\Cable Collection Advices - 11.xls")
y.Sheets(destsheetName).Range("C8").PasteSpecial xlPasteValues
SourceRange2.Copy
y.Sheets(destsheetName).Range("G8").PasteSpecial xlPasteValues
SourceRange3.Copy
y.Sheets(destsheetName).Range("I8").PasteSpecial xlPasteValues
SourceRange4.Copy
y.Sheets(destsheetName).Range("J8").PasteSpecial xlPasteValues
lastRow2 = wsDest.Range("C" & Rows.Count).End(xlUp).Row
y.Sheets(destsheetName).Range("A8:A" & lastRow2 + 7).Value = Format(Now(), "dd.mm.yyyy")
y.Sheets(destsheetName).Range("B5").Value = Format(Now(), "dd.mm.yyyy")
Application.DisplayAlerts = False
Do While Len(FolDir) > 0
If FolDir Like "Cable Collection Advices - " & "*" & ".xlsx" Then
StrNum = Right(Left(FolDir, 32), 5)
'MsgBox "StrNum" & StrNum
NumStr = CInt(StrNum)
If NumStr > MaxNum Then
MaxNum = NumStr
End If
End If
FolDir = Dir
'Next FileNm
Loop
MaxStr = CStr(Format(MaxNum + 1))
NewName = FolderStr & "Cable Collection Advices - " & MaxStr & ".xlsx"
y.SaveAs Filename:=NewName, FileFormat:=51, CreateBackup:=False
y.Close SaveChanges:=False
ActiveWorkbook.Worksheets("Filtered Data").Delete
wsw.Activate
MM1
Else
MsgBox ("No data")
End If
Sub MM1() 'close all the worksheet autofilter
Dim ws As Worksheet
For Each ws In Worksheets
'ws.AutoFilterMode = ShowAllData
With ws
If .AutoFilterMode Then
If .FilterMode Then
.ShowAllData
End If
End If
End With
Next ws
End Sub
Just yesterday I've made a multiple fields filter - it collected the multiple criteria and put the list on another sheet.
1.- creating 2-dimention array Result(a,b) - where a in horizontal dimention and b- vertical dimension of the table write the filtered table into this array
2. - create a user function to put the lines in Result(a,b) that doesn't satisfy criteria to 0 (in my case there were text data, so i used 0, you can use anything you can identify)
Function is like this
Function ArrFilter(ByVal fVal, ByVal ColNbr)'fVal - value to filter, ColNbr - number of column you filter in
For i = 1 To count7
If CStr(fVal) <> CStr(Result(ColNbr, i)) Then
For j = 1 To count3
Result(j, i) = 0
Next j
End If
Next i
End Function
Put your criteria dimension in a loop if you have array of criteria Criteria() and column 2
For Each x in Criteria
Call ArrFilter(x, 2)
Next x
Then you write the result into table, selecting those that are not 0
count=0
For i=b
If Result(2,i)<>0 Then
For j=a
count=count+1
Cells(count,j)=Result(j,i)
Next j
End If
Next i
I need to delete sheets not mentioned in the given list(Range is A7:A350).
I found this vba but the problem is it deletes all the sheets from my workbook, maybe because sheetname is in numeric. I would really appreciate any help.
Sub Deletenotinlist()
Dim i As Long
Dim cnt As Long
Dim xWb, actWs As Worksheet
Set actWs = ThisWorkbook.ActiveSheet
cnt = 0
Application.DisplayAlerts = False
For i = Sheets.Count To 1 Step -1
If Not ThisWorkbook.Sheets(i) Is actWs Then
xWb = Application.Match(Sheets(i).Name, actWs.Range("A7:A350"), 0)
If IsError(xWb) Then
ThisWorkbook.Sheets(i).Delete
cnt = cnt + 1
End If
End If
Next
Application.DisplayAlerts = True
If cnt = 0 Then
MsgBox "Not find the sheets to be seleted", vbInformation, "Kutools for Excel"
Else
MsgBox "Have deleted" & cnt & "worksheets"
End If
End Sub
I think I would do it this way.
Sub DeleteSheets()
Dim sht As Worksheet
Dim rng As Range
Set rng = Sheets("Sheet1").Range("A2:A10")
Application.DisplayAlerts = False
For Each sht In ActiveWorkbook.Worksheets
If Application.CountIf(rng, sht.Name) = 0 Then
sht.Delete
End If
Next sht
Application.DisplayAlerts = True
End Sub
What you try doing can be accomplished in many ways, but I tried adapting your code to place the missing sheets name in an array and select them at the end. If selection is convenient, you can replace Select with Delete:
Sub Deletenotinlist()
Dim i As Long, cnt As Long, xWb, actWs As Worksheet, lastR As Long, arrSh(), k As Long
Set actWs = ThisWorkbook.ActiveSheet
lastR = actWs.Range("A" & actWs.rows.count).End(xlUp).row
ReDim arrSh(ThisWorkbook.Sheets.count - 1)
cnt = 0
For i = 1 To Sheets.count
If Not ThisWorkbook.Sheets(i) Is actWs Then
xWb = Application.match(Sheets(i).Name, actWs.Range("A7:A" & lastR), 0)
If IsError(xWb) Then
arrSh(k) = CStr(ThisWorkbook.Sheets(i).Name): k = k + 1
cnt = cnt + 1
End If
End If
Next
ReDim Preserve arrSh(k - 1) 'keep only the filled array elements
Sheets(arrSh).Select 'You can replace 'Select' with 'Delete', if it returns correctly
If cnt = 0 Then
MsgBox "Not find the sheets to be seleted", vbInformation, "Kutools for Excel"
Else
MsgBox "Have deleted " & cnt & " worksheets"
End If
End Sub
It processes all existing values in column A:A, starting from the 7th row.
But I'm afraid that the range you try processing does not contain any existing sheet name...
In order to test the above supposition, please run the next test sub, which will place all existing sheets name in column B:B, starting from the 7th row. Then delete some rows and run the previous code, replacing "A" with "B" in lastR = actWs.Range("A" &... and actWs.Range("A7:A" & lastR). The code should select all missing sheets:
Sub testArraySheets()
Dim arrSh, ws As Worksheet, k As Long
ReDim arrSh(ActiveWorkbook.Sheets.count - 1)
For Each ws In ActiveWorkbook.Sheets
If Not ws Is ActiveSheet Then
arrSh(k) = ws.Name: k = k + 1
End If
Next
ActiveSheet.Range("B7").Resize(UBound(arrSh) + 1, 1).Value = Application.Transpose(arrSh)
End Sub
I have several columns with headers in one excel workbook, I want to copy some of these columns into another workbook.
Let’s say I have my origin workbook:
Ident|Name|Code|Part|Desc|U|Total
These are the headers of the columns with some data below them.
And I want to copy only the data in the columns Ident, Code and Part in another workbook that has the same headers but in a different order with the exception that one header has a different name:
Code|Ident|Piece
It is blank and Piece corresponds to Part.
So I want a code that takes the data from the origin workbook and copy it to the destination workbook. Also if possible I’d like that you can choose the original workbook from a file as I have different excel files to choose from.
Thank you for your answers. I have never used VBA and I’m trying to learn.
I have the following code that lets you choose the data you want manually but I want something similar that does it automatically after recognizing the headers.
Sub ImportDatafromotherworksheet()
Dim wkbCrntWorkBook As Workbook
Dim wkbSourceBook As Workbook
Dim rngSourceRange As Range
Dim rngDestination As Range
Set wkbCrntWorkBook = ActiveWorkbook
With Application.FileDialog(msoFileDialogOpen)
.Filters.Clear
.Filters.Add "Excel 2007-13", "*.xlsx; *.xlsm; *.xlsa"
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
Workbooks.Open .SelectedItems(1)
Set wkbSourceBook = ActiveWorkbook
Set rngSourceRange = Application.InputBox(prompt:="Select source range", Title:="Source Range", Default:="A1", Type:=8)
wkbCrntWorkBook.Activate
Set rngDestination = Application.InputBox(prompt:="Select destination cell", Title:="Select Destination", Default:="A1", Type:=8)
rngSourceRange.Copy rngDestination
rngDestination.CurrentRegion.EntireColumn.AutoFit
wkbSourceBook.Close False
End If
End With
End Sub
I add here some part I modified:
arrC = Split("CODE|ident|Piece", "|")
lastColO = shO.Cells(1, Cells.Columns.Count).End(xlToLeft).Column
arrO = shO.Range(shO.Cells(1, 1), shO.Cells(1, lastColO)).Value
'Copy the columns:
arrC = Split("CODE|ident|Piece", "|")
lastColO = shO.Cells(1, Cells.Columns.Count).End(xlToLeft).Column
arrO = shO.Range(shO.Cells(1, 1), shO.Cells(1, lastColO)).Value
'Copy the columns:
For j = 0 To UBound(arrC)
If arrC(j) = "Ident" Then strH = "ident" Else strH = arrC(j)
If arrC(j) = "Code" Then strH = "CODE" Else strH = arrC(j)
If arrC(j) = "Piece" Then strH = "Part" Else strH = arrC(j)
For i = 1 To UBound(arrO, 2)
If arrO(1, i) = strH Then
lastRowO = shO.Cells(Rows.Count, i).End(xlUp).Row 'last row of the found orig header column
lastRowC = shC.Cells(Rows.Count, j + 1).End(xlUp).Row 'last row of toCopy sheet header column
arrTransf = shO.Range(shO.Cells(2, i), shO.Cells(lastRowO, i)).Value
Set copyCell = shC.Range(shC.Range("A1"), shC.Cells(1, lastColO)).Find(arrC(j))
If copyCell Is Nothing Then MsgBox "There is not a column named """ & _
arrC(j) & """ in the page to Copy.": Exit Sub
copyCell.Offset(1, 0).Resize(UBound(arrTransf, 1), UBound(arrTransf, 2)).Value = arrTransf
End If
Next i
Next j
End Sub
Try this code, please. It copies columns from the active sheet to shC worksheet, which must be set in the code below:
Sub moveColumnsContent()
Dim shO As Worksheet, shC As Worksheet, lastRowO As Long, lastRowC As Long
Dim arrO As Variant, arrC As Variant, lastColO As Long, lastColC As Long
Dim El As Variant, arrTransf As Variant, strH As String, copyCell As Range
Dim wbNumb As Variant, wb As Workbook, ws As Worksheet, strWB As String
Dim WbC As Workbook, sh As Worksheet, strWh As String, shNunb As String
Dim i As Long, j As Long
Set shC = ActiveSheet
WbSelection:
For i = 1 To Workbooks.count
strWB = strWB & Workbooks(i).Name & " - " & i & vbCrLf
Next i
wbNumb = InputBox("Please, write the the right workbook name number to be chosen:" & vbCrLf & _
vbCrLf & strWB, "Choose the workbook from where to copy columns!", 1)
If wbNumb = "" Then MsgBox "You did not select anything and code stops!"
Exit Sub
If IsNumeric(wbNumb) Then
On Error Resume Next
Set WbC = Workbooks(CLng(wbNumb))
if Err.Number<> 0 Then
Err.Clear: On Error GoTo 0:Exit Sub
End If
On Error GoTo 0
Else
MsgBox "Please select the number to the right side of the chosen workbook!": GoTo WbSelection
End If
WsSelection:
For i = 1 To WbC.Worksheets.count
strWh = strWh & WbC.Worksheets(i).Name & " - " & i & vbCrLf
Next
shNunb = InputBox("Please, write the the right sheet name number to be chosen:" & vbCrLf & _
vbCrLf & strWh, "Select the worksheet to be used for copying the columns!", 1)
If shNunb = "" Then MsgBox "Please select a worksheet number to be selected for copying columns!": _
GoTo WsSelection
Set shO = WbC.Worksheets(CLng(shNunb))
arrC = Split("Code|Ident|Piece", "|")
lastColO = shO.Cells(1, Cells.Columns.count).End(xlToLeft).Column
arrO = shO.Range(shO.Cells(1, 1), shO.Cells(1, lastColO)).value
'Copy the columns:
For j = 0 To UBound(arrC)
If arrC(j) = "Piece" Then strH = "Part" Else strH = arrC(j)
For i = 1 To UBound(arrO, 2)
If arrO(1, i) = strH Then
lastRowO = shO.Cells(Rows.count, i).End(xlUp).Row 'last row of the found orig header column
lastRowC = shC.Cells(Rows.count, j + 1).End(xlUp).Row 'last row of toCopy sheet header column
arrTransf = shO.Range(shO.Cells(2, i), shO.Cells(lastRowO, i)).value
Set copyCell = shC.Range(shC.Range("A1"), shC.Cells(1, lastColO)).Find(arrC(j))
If copyCell Is Nothing Then MsgBox "There is not a column named """ & _
arrC(j) & """ in the page to Copy.": Exit Sub
copyCell.Offset(1, 0).Resize(UBound(arrTransf, 1), UBound(arrTransf, 2)).value = arrTransf
End If
Next i
Next j
End Sub
If you will need more headers in the sheet to copy, it is enough to add them in "Code|Ident|Piece" string.
Now, trying to think how it would be more convenient for you to use it, probably, a better way would be to name the sheet where from the columns will be copied, in a specific way (maybe "MasterSheet") and copy the columns to the active one. Or, iterate between all Workbook sheets and do this process automatically. But, please, try the code as it is and let me know how looks more convenient for you.
If your intention is to extract a three columns set in the fixed order Code|Ident|Part=Piece copying them to the first three target columns A:C, you may try the following Rearrange procedure executing these steps:
[0-1] get source data
[2 ] rearrange columns of source data in a given order by a one-liner instead of copying separate columns arrays each time
[3 ] write (rearranged) data to target sheet
Sub Rearrange(src As Worksheet, tgt As Worksheet)
'Purpose: extract and rearrange data array columns
'Author: https://stackoverflow.com/users/6460297/t-m
With src
'[0] get last row of source data in column A:A (Ident)
Dim lastRow As Long: lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
'[1] assign data to (1-based) 2-dim variant datafield array
Dim data: data = .Range("A2:G" & lastRow)
'[2] rearrange columns
' where Array(3,1,4) gets the 3rd, 1st and 4th column only
' (and Evaluate("ROW(1:nnn)") gets the entire row set)
data = Application.Index(data, Evaluate("ROW(1:" & (lastRow - 1) & ")"), Array(3, 1, 4))
End With
'[3] write (rearranged) data to target sheet
tgt.Range("A2").Resize(UBound(data), 3) = data
End Sub
If, however you are confronted with a variable target column structure you might play around with Moving columns based on header name and change it to your needs :-)
This should work, you only need to tweak the target sheet and, if it were the case, add more cases where origin/target have different column names:
Option Explicit
Sub Main()
Dim arrOrigin As Variant: arrOrigin = GetArrayFromSheet
Dim OriginHeaders As New Dictionary: Set OriginHeaders = GetOriginHeaders(arrOrigin)
With ThisWorkbook.Sheets("Your target sheet name") 'change this name
Dim arrTarget As Variant: ReDim arrTarget(1 To UBound(arrOrigin), _
1 To .UsedRange.Columns.Count)
'Last row on column 1 (or column A)
Dim LastRow As Long: LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
End With
Dim TargetHeaders As New Dictionary: Set TargetHeaders = GetTargetHeaders(arrTarget)
Dim i As Long
Dim Key As Variant
Dim OriginColumn As Long, TargetColumn As Long
Dim x As Long: x = 1
For i = 2 To UBound(arrOrigin)
For Each Key In TargetHeaders.Keys
OriginColumn = OriginHeaders(Split(TargetHeaders(Key), "\")(0))
TargetColumn = Split(TargetHeaders(Key), "\")(1)
arrTarget(x, TargetColumn) = arrOrigin(i, OriginColumn)
Next Key
Next i
ThisWorkbook.Sheets("Your target sheet name").Range("A" & LastRow).Resize(UBound(arrTarget), UBound(arrTarget, 2)).Value = arrTarget
End Sub
Private Function GetArrayFromSheet() As Variant
Dim wb As Workbook: Set wb = FilePicker
Dim ws As Worksheet
For Each ws In wb.Sheets
If ws.Name Like "* Annex 1" Then
GetArrayFromSheet = ws.UsedRange.Value
wb.Close False
Exit Function
End If
Next ws
End Function
Private Function FilePicker() As Workbook
With Application.FileDialog(msoFileDialogOpen)
.Filters.Clear
.Filters.Add "Excel 2007-13", "*.xlsx; *.xlsm; *.xlsa"
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
Set FilePicker = Workbooks.Open(.SelectedItems(1))
Else
MsgBox "No file was selected, the procedure will end"
End
End If
End With
End Function
Private Function GetOriginHeaders(arr As Variant) As Dictionary
Set GetOriginHeaders = New Dictionary
Dim i As Long
For i = 1 To UBound(arr, 2)
GetOriginHeaders.Add arr(1, i), i
Next i
End Function
Private Function GetTargetHeaders(arr As Variant) As Dictionary
Set GetOriginHeaders = New Dictionary
Dim i As Long
Dim MyHeader As String
For i = 1 To UBound(arr, 2)
MyHeader = arr(1, i)
Select Case MyHeader
Case "Piece"
MyHeader = "Part"
'..More cases for different names
End Select
TargetHeaders.Add arr(1, i), MyHeader & "\" & i
Next i
End Function
In Workbook 1, I have a spreadsheet that tracks the inventory of meat products.
Row 1 is used for the column names: "Parcel Tracking Number" in column A and other data related to the parcel in the other columns (Such as "Date of export", "Weight" and "Content" among other things).
Column I describes the parcel's "Content" and these parcels all contain "Meat".
The rows of information in this spreadsheet have been copied from Workbook 2 which contains parcels that contain "Meat", "Cheese", "Milk" and "Eggs" in column I.
Both workbooks have the same columns names in row 1.
In workbook 1, I update the data on some of the rows and I want the change to be applied in Workbook 2 by copying workbook 1 rows and pasting them in Workbook 2 in the rows where the "Parcel Tracking Number" in column A matches.
So far, I have the code to copy all the "Meat" parcel rows from Workbook 2 and paste them in Workbook 1 but now I need help with this new situation.
The program is executed by opening Workbook 2 and pressing a command button which opens workbook 1 and starts copying the rows to the Meat worksheet.
Here it is:
Private Sub CommandButton1_Click()
Application.ScreenUpdating = False ' Screen Update application turned off in order to make program run faster
Dim y As Workbook '
Dim sh As Worksheet '
Set y = Workbooks.Open("\\SCF1\USERS-D\Robert\My Documents\Excel VBA code\Meat.xlsx") '
a = ThisWorkbook.Worksheets("Products").Cells(Rows.Count, 1).End(xlUp).Row
Set sh = Workbooks("Meat.xlsx").Worksheets("Meat")
With ThisWorkbook.Worksheets("Products")
For i = 2 To a ' value ''i'' is the column number
If ThisWorkbook.Worksheets("Products").Cells(i, 9).Value Like "*Meat*" And IsError(Application.Match(.Cells(i, "A").Value, sh.Columns("A"), 0)) Then ' this sets the condition for which the data can only be copied if the row has '' Meat '' included in the 9th column (substance) and if the row is not already copied in the Meat worksheet.
ThisWorkbook.Worksheets("Products ").Rows(i).Copy
Workbooks("Meat.xlsx").Worksheets("Meat").Activate
b = Workbooks("Meat.xlsx").Worksheets("Meat ").Cells(Rows.Count, 1).End(xlUp).Row
Workbooks("Meat.xlsx").Worksheets("Meat").Cells(b + 1, 1).Select
ActiveSheet.Paste
ThisWorkbook.Worksheets("Products").Activate
End If
Next
On Error Resume Next '1004 error kept appearing so this function allows us to continue to next step without error appearing
ThisWorkbook.Worksheets("Products").Cells(1, 1).Select
End With
MsgBox "All rows from Products worksheet have been copied."
Application.ScreenUpdating = True
End Sub
Any help is greatly appreciated. Thanks.
Use Find to check if Tracking Number exists and to locate row when transferring data back to Products.
Option Explicit
Sub CommandButton1_Click()
' update meat
Const PATH = "\\SCF1\USERS-D\Robert\My Documents\Excel VBA code\"
Const WB_NAME = "Meat.xlsx"
Dim wb As Workbook, ws As Worksheet, iLastRow As Long, iRow As Long
Dim wbTarget As Workbook, wsTarget As Worksheet, iTargetRow As Long
Set wbTarget = Workbooks.Open(PATH & WB_NAME)
Set wsTarget = wbTarget.Sheets("Meat")
iTargetRow = wsTarget.Cells(Rows.count, 1).End(xlUp).Row + 1
Set wb = ThisWorkbook
Set ws = wb.Sheets("Products")
iLastRow = ws.Cells(Rows.count, 1).End(xlUp).Row
Dim sContent As String, sTrackId As String
Dim res As Variant, count As Long
'Application.ScreenUpdating = False
count = 0
For iRow = 2 To iLastRow
sTrackId = ws.Cells(iRow, "A")
sContent = ws.Cells(iRow, "I")
If LCase(sContent) Like "*meat*" Then
' check not already on sheet
Set res = wsTarget.Range("A:A").Find(sTrackId)
If (res Is Nothing) Then
ws.Rows(iRow).Copy wsTarget.Cells(iTargetRow, 1)
iTargetRow = iTargetRow + 1
count = count + 1
End If
End If
Next
'wbTarget.Save
'wbTarget.Close
MsgBox count & " rows inserted from Products worksheet."
'Application.ScreenUpdating = True
End Sub
Sub CommandButton2_Click()
' update product
Const PATH = "\\SCF1\USERS-D\Robert\My Documents\Excel VBA code\"
Const WB_NAME = "Meat.xlsx"
Dim wb As Workbook, ws As Worksheet, iRow As Long
Dim wbSource As Workbook, wsSource As Worksheet, iLastSourceRow As Long
Set wbSource = Workbooks.Open(PATH & WB_NAME, False, True) 'no link update, read-only
Set wsSource = wbSource.Sheets("Meat")
iLastSourceRow = wsSource.Cells(Rows.count, 1).End(xlUp).Row + 1
Set wb = ThisWorkbook
Set ws = wb.Sheets("Products")
Dim sTrackId As String
Dim res As Variant, count As Long
'Application.ScreenUpdating = False
count = 0
For iRow = 2 To iLastSourceRow
sTrackId = wsSource.Cells(iRow, "A")
' find row on product sheet
Set res = ws.Range("A:A").Find(sTrackId)
If (res Is Nothing) Then
MsgBox "Could not update " & sTrackId, vbExclamation
Else
wsSource.Rows(iRow).Copy ws.Cells(res.Row, 1)
count = count + 1
End If
Next
wbSource.Close
MsgBox count & " rows updated from Meat workbook."
'Application.ScreenUpdating = True
End Sub
I have an API call that pulls data relating to 34 individual sites. Each site has a varying number of assets within it, each with a unique identifier.
I am trying to write a macro that will copy and paste the data for specific sites into their own individual worksheet within the file. The basic concept of this I am familiar with but I am struggling with the ranges I need to specify.
So basically, I need the macro to work its way down Column A of the sheet called Raw Data and identify any rows where the Site name (Value in column A) matches one of the Sheet names. It should then copy the Rows from A to H with that site name and paste into the respective site sheet in rows A to H.
The values in Column A will always match one of the other sheets in the workbook.
Example image that might help explain a bit better:
Apologies in advance if my explanation is not very clear. I have very limited experience using macros so I am not sure if my way of explaining what I want to achieve is understandable or if at all possible.
I am very keen to learn however and any guidance you fine folk could offer would be very much appreciated.
Welcome!
Try this one
Function ChkSheet(SheetName As String) As Boolean
For i = 1 To Worksheets.Count
If Worksheets(i).Name = SheetName Then
ChkSheet = True
Exit Function
End If
Next
ChkSheet = False
End Function
Sub test()
Dim i, j, k As Long
Dim wsRaw As Worksheet
Dim Aux As String
Set wsRaw = Worksheets("Raw Data")
For i = 1 To wsRaw.Range("A:A").SpecialCells(xlCellTypeLastCell).Row
If ChkSheet(wsRaw.Cells(i, 1).Value2) Then
Aux = wsRaw.Cells(i, 1).Value2
k = Worksheets(Aux).Range("A:A").SpecialCells(xlCellTypeLastCell).Row + 1
For j = 1 To 8
Worksheets(Aux).Cells(i + k, j).Value2 = wsRaw.Cells(i, j).Value2
Next
Else
Worksheets.Add.Name = wsRaw.Cells(i, 1).Value2
Aux = wsRaw.Cells(i, 1).Value2
k = 2
For j = 1 To 8
Worksheets(Aux).Cells(i + k, j).Value2 = wsRaw.Cells(i, j).Value2
Next
End If
Next
End Sub
So the Function ChkSheet will check if the sheet exist (you don´t need to create them) and the procedure test will follow all the items that you have in your "Raw Data" worksheet and it will copy to the last used row of every sheet.
And please, even for a newbie, google, read, get some information and when you get stacked, ask for help. This forum is not for giving solutions with not effort.
Good morning all,
David, thanks very much for your help with this. I really didn't want you to think I was trying to get someone to give me the answer and I had tried a few other things before asking the question, but I neglected to show any evidence of my workings. Rookie mistake and I apologise for this.
Having done a bit more research online and with a good dollop of help from a much more experienced colleague I have got the below code using advance filter which works perfectly for what I need.
I thought I would share it here in case it is of any use to others in the future.
Option Explicit
Dim RawDataCol As String
Dim ListCol As String
Dim AdvRng As String
Dim RawDataRng As String
Dim SiteAbrRng As String
Dim ShiftCols As String
Private Sub SetParameters()
'Cell Address where RawData is pasted to each of the site sheets
RawDataCol = "A2"
'Column where the Unique List is cleared and pasted
ListCol = "L"
'Advanced Filter Range
AdvRng = "A1:K2"
'Pasted Raw Data Columns on each sheet
RawDataRng = "A2:K"
'Site Abr gets pasted to the address during loop
SiteAbrRng = "A2"
'Range that gets deleted after pasting Raw Data to each sheet
ShiftCols = "A2:K2"
End Sub
Sub CopyDataToSheets()
On Error GoTo ErrorHandler
AppSettings (True)
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
Dim wbk As Workbook
Dim sht_RawData As Worksheet, sht_target As Worksheet, sht_AdvancedFilter As Worksheet, sht_TurbineData As Worksheet
Dim tbl_RawData As ListObject
Dim LastRow1 As Long, LastRow2 As Long, UniqueListCount As Long
Dim MyArr As Variant
Dim ArrTest As Boolean
Dim x As Long, AdvRowNo As Long
Set wbk = ThisWorkbook
SetParameters
Set sht_RawData = wbk.Worksheets("Raw Data")
Set sht_AdvancedFilter = wbk.Worksheets("Advanced Filter")
Set sht_TurbineData = wbk.Worksheets("Turbine Data")
Set tbl_RawData = sht_RawData.ListObjects("_00")
'clear unqie list of SiteAbr
With sht_TurbineData
LastRow1 = .Cells(Rows.Count, 12).End(xlUp).Row
If LastRow1 > 1 Then
'sht_TurbineData.Range("L1:L" & LastRow1).ClearContents
sht_TurbineData.Range(ListCol & 1 & ":" & ListCol & LastRow1).ClearContents
End If
End With
'Copy Unqiue list of SiteAbr to Turbie Data Sheet
tbl_RawData.Range.Columns(1).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=sht_TurbineData.Range(ListCol & 1), _
Unique:=True
LastRow1 = sht_TurbineData.Cells(Rows.Count, sht_TurbineData.Range(ListCol & 1).Column).End(xlUp).Row
'Sort Unique List
sht_TurbineData.Range("L1:L" & LastRow1).Sort _
Key1:=sht_TurbineData.Range("L1"), _
Order1:=xlAscending, _
Header:=xlYes
'Load unique site Abr to array
With sht_TurbineData
'MyArr = Application.Transpose(.Range("L2:L" & LastRow1))
MyArr = Application.Transpose(.Range(ListCol & 2 & ":" & ListCol & LastRow1))
UniqueListCount = LastRow1 - 1
End With
'Test Array conditions for 0 items or 1 item
ArrTest = IsArray(MyArr)
If UniqueListCount = 1 Then
MyArr = Array(MyArr)
ElseIf UniqueListCount = 0 Then
GoTo ExitSub
End If
For x = LBound(MyArr) To UBound(MyArr)
Set sht_target = wbk.Worksheets(MyArr(x))
With sht_target
'Find the last non blank row of the target paste sheet
LastRow2 = .Cells(Rows.Count, 1).End(xlUp).Row
'Clear contents if the Last Row is not the header row
If LastRow2 > 1 Then
.Range(RawDataRng & LastRow2).ClearContents
End If
sht_AdvancedFilter.Range(SiteAbrRng) = MyArr(x)
'Filter Source Data and Copy to Target Sheet
tbl_RawData.Range.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=sht_AdvancedFilter.Range(AdvRng), _
CopyToRange:=.Range(RawDataCol), _
Unique:=False
'Remove the first row as this contains the headers
.Range(ShiftCols).Delete xlShiftUp
End With
Next x
ExitSub:
SecondsElapsed = Round(Timer - StartTime, 3)
AppSettings (False)
'Notify user in seconds
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
Exit Sub
ErrorHandler:
MsgBox (Err.Number & vbNewLine & Err.Description)
GoTo ExitSub
End Sub
Sub ClearAllSheets()
Dim tbl_SiteList As ListObject
Dim wbk As Workbook
Dim sht_target As Worksheet, sht_TurbineData As Worksheet
Dim MyArray As Variant
Dim x As Long, LastRow As Long
Set wbk = ThisWorkbook
Set sht_TurbineData = wbk.Worksheets("Turbine Data")
Set tbl_SiteList = sht_TurbineData.ListObjects("SiteList")
SetParameters
MyArray = Application.Transpose(tbl_SiteList.DataBodyRange)
For x = LBound(MyArray) To UBound(MyArray)
Set sht_target = wbk.Worksheets(MyArray(x))
LastRow = sht_target.Cells(Rows.Count, 1).End(xlUp).Row
If LastRow > 1 Then
sht_target.Range("A2:K" & LastRow).ClearContents
End If
Next x
End Sub
Private Sub AppSettings(Opt As Boolean)
If Opt = True Then
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
ElseIf Opt = False Then
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End If
End Sub
Thanks again to all who answered and especially to you David. Although I have only used the basic principles from what you offered, it was extremely useful to help me understand what I needed to do in order to get the data to copy into the correct sheets.
Many thanks,
MrChrisP