Copying Excel data from multiple worksheets into one single sheet - vba

I have tried searching the internet for various answers to this question but cannot find the right answer. I have an Excel Workbook with worksheets represent each day of the month. In each of these sheets the format is the same (except on Saturdays and Sundays) and the sheets contain call stats. It is presented in the following format:
00:00 00:30 0 4 6 3 4 8 0 1 0 0 0
00:00 00:30 0 0 2 7 4 1 0 0 3 3 0
00:00 00:30 7 0 7 5 2 8 6 1 7 9 0
I need to copy this data into 1 single sheet that lists all the data. Basically it appends the new data on to the bottom of the old data. So it will be one big list.
How can this be done? All I can see is how to produce a total from multiple data by adding all the values together. I just need to list the data as one big list.

MASSIVE EDIT:
As with last chat with Iain, the correct parameters have been set. I have removed the last few code snippets as they are quite not right. If anyone is still interested, please check the edit history.
Hopefully, this is the final edit. ;)
So, the correct conditions needed are:
Month name in sheet. We used an Input Box for this.
We check for number of rows. There are three conditions: 157 rows total, 41 rows total, and all else.
The following subroutine will do the trick.
Sub BlackwoodTransfer()
Dim Summ As Worksheet, Ws As Worksheet
Dim ShName As String
Dim nRow As Long
Set Summ = ThisWorkbook.Sheets("Summary")
ShName = InputBox("Enter month for Call Flow in mmmm format (ie. November, etc.):") & " Call Flow"
'Returns November Call Flow. This means it will target every sheet that has November Call Flow in its name.
Application.ScreenUpdating = False
For Each Ws In ThisWorkbook.Worksheets
If InStr(1, Ws.Name, ShName) > 0 Then
'Starting from first character of the sheet's name, if it has November, then...
nRow = Summ.Cells(Rows.Count, 1).End(xlUp).Row + 1
'... get the next empty row of the Summary sheet...
Select Case Ws.Cells(Rows.Count, 1).End(xlUp).Row
'... check how many rows this qualified sheet has...
Case 157
'... if there are 157 rows total...
Ws.Range(Cells(57,1),Cells(104,13)).Copy
'... copy Rows 57 to 104, 13 columns wide...
Summ.Range("A" & nRow).PasteSpecial xlPasteAll
'... and paste to next empty row in Summary sheet.
Case 41
Ws.Range(Cells(23,1),Cells(126,13)).Copy
Summ.Range("A" & nRow).PasteSpecial xlPasteAll
Case Else
Ws.Range(Cells(23,1),Cells(30,13)).Copy
Summ.Range("A" & nRow).PasteSpecial xlPasteAll
End Select
End If
Next Ws
Application.ScreenUpdating = True
End Sub
#Iain: Check out the comments and cross reference them with the MSDN database. That should explain what each function/method is doing exactly. Hope this helps!

Sub CombineSheets()
Dim ws As Worksheet, wsCombine As Worksheet
Dim rg As Range
Dim RowCombine As Integer
Set wsCombine = ThisWorkbook.Worksheets.Add(ThisWorkbook.Worksheets(1))
wsCombine.Name = "Combine"
RowCombine = 1
For Each ws In ThisWorkbook.Worksheets
If ws.Index <> 1 Then
Set rg = ws.Cells(1, 1).CurrentRegion
rg.Copy wsCombine.Cells(RowCombine, 2)
wsCombine.Range(Cells(RowCombine, 1), Cells(RowCombine + rg.Rows.Count - 1, 1)) = ws.Name
RowCombine = RowCombine + rg.Rows.Count
End If
Next
wsCombine.Cells(1, 1).EntireColumn.AutoFit
Set rg = Nothing
Set wsCombine = Nothing
End Sub

Create a worksheet "Summary" which is to contain all the merged data.
Open ThisWorkBook (simply press ALT+F11 in your excel workbook. A new window will open. Your worksheet name will be visible on the left hand side. Keep expanding till you see ThisWorkBook)
Double click ThisWorkBook and add the following code in it:
Sub SummurizeSheets()
Dim ws As Worksheet
Application.Screenupdating = False
Sheets("Summary").Activate
For Each ws In Worksheets
If ws.Name <> "Summary" Then
ws.Range("F46:O47").Copy
ActiveSheet.Paste Range("A65536").End(xlUp).Offset(1, 0)
End If
Next ws
End Sub

Sub AddToMaster()
'this macro goes IN the master workbook
Dim wsMaster As Worksheet, wbDATA As Workbook
Dim NextRow As Long, LastRow As Long
Dim FileName As String
Dim FolderPath As String
Dim n As Long
Dim i
Set wsMaster = ThisWorkbook.Sheets("Sheet1")
'Specify the folder path
FolderPath = "D:\work\"
'specifying file name
FileName = Dir(FolderPath & "*.xls*")
Do While FileName <> ""
NextRow = wsMaster.Range("A" & Rows.Count).End(xlUp).Row + 1
Set wbDATA = Workbooks.Open(FolderPath & FileName)
With wbDATA.Sheets("product_details")
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
' If LastRow > 5 Then
For i = 2 To LastRow
.Range("A2:j" & i).Copy
wsMaster.Range("A" & NextRow).PasteSpecial xlPasteValues
'Set NextRow = NextRow
Next i
End With
FileName = Dir()
Loop
wbDATA.Close False
End Sub

Related

vba - new sheets from columns, paste column A if X in column X to new sheet

Looking to generate a new sheet for each column in a workbook. (done, pasted below). Next step is to paste the value of Column A if a value is in column 'X'.
Name | Email | Course 101 | Course 203 |
John | john #| X | X |
Jane |Jane# | X | |
Result would be two sheets, (Course 101, Course 203) controlled with a 'Range' function during the sheet generation code.
Part I'm stuck on, is how to paste John's name on the Course 101 and Course 203 sheet and Jane only on the Course 101 sheet.
Here's the code that works for the sheet generation (I think found on here :) )
Sub AddSheets()
Dim cell As Excel.Range
Dim wsWithSheetNames As Excel.Worksheet
Dim wbToAddSheetsTo As Excel.Workbook
Set wsWithSheetNames = ActiveSheet
Set wbToAddSheetsTo = ActiveWorkbook
For Each cell In wsWithSheetNames.Range("A1:d1")
With wbToAddSheetsTo
.Sheets.Add after:=.Sheets(.Sheets.Count)
On Error Resume Next
ActiveSheet.Name = cell.Value
If Err.Number = 1004 Then
Debug.Print cell.Value & " already used as a sheet name"
End If
On Error GoTo 0
End With
Next cell
End Sub
The code above will work to insert the worksheets but it does not do anything after that. Based off the script above I wrote up something similar that does what you want but with slightly easier to understand variables and terms.
The code pasted below requires you to enter the main worksheet name or just set the main worksheet's name to "Main".
This code should be a lot easier to understand since it breaks the process up into 2 blocks.
Sub FillCourseWorksheets()
Dim wb As Workbook, cws As Worksheet, ws As Worksheet, found As Boolean
Dim crw As Long, rw As Long, col As Integer, wsName As String
Dim CheckString As String, student As String, lastRow As Long
Dim lastCol As Integer, courseName As String, resultRow As Long
'this code depends on the main sheet to have the headers in row 1
'----------------------------------------------------------
wsName = "Main" 'set this to the name of your main worksheet
'----------------------------------------------------------
'set up
Set wb = ThisWorkbook
'if you get an error here set the sheet name to main
Set cws = wb.Worksheets(wsName)
'use the .end to find the last column and row similar to CTRL + Right/Down
lastRow = cws.Range("A1").End(xlDown).Row
lastCol = cws.Range("A1").End(xlToRight).Column
'go through each column and add a worksheet if needed
For col = 3 To lastCol
CheckString = cws.Cells(1, col).Value
'check if the worksheet already exists
found = False
For Each ws In wb.Worksheets
If ws.Name = CheckString Then
found = True
Exit For
End If
Next ws
If found = False Then 'didnt find the sheet. Add it to the workbook
Set ws = wb.Worksheets.Add(after:=wb.Worksheets(wb.Worksheets.Count)) 'add the worksheet
ws.Name = CheckString 'name it
ws.Range("A1").Value = "Name"
cws.Activate 'activate the main page after insert
End If
Next col
'all worksheets added go through columns again and add data to each worksheet
For col = 3 To lastCol
courseName = cws.Cells(1, col).Value
Set ws = wb.Worksheets(courseName) 'identify the worksheet to use
For checkrow = 2 To lastRow
If cws.Cells(checkrow, col).Value <> "" Then
student = cws.Range("A" & checkrow).Value
'set the resultrow and check if there is no data
If ws.Range("A2").Value = "" Then
resultRow = 2
Else
resultRow = ws.Range("A1").End(xlDown).Row + 1
End If
ws.Range("A" & resultRow).Value = student 'print out the student
End If
Next checkrow
Next col
MsgBox "done"
End Sub
Save your workbook before running this and let me know if you have any trouble.

Fastest way to return multiple match values in Excel

I'm trying to see if there's a macro that can speed up a multiple match formula I'm using in a file.
The formula is:
=IFERROR(INDEX(Data!$D:$D,SMALL(IF('Department 1'!$A$1=Data!$B:$B,ROW(Data!$B:$B)-MIN(ROW(Data!$B:$B))+1,""), ROW(Data!A1))),"Enter New Client Name")
In a workbook, There's three worksheets: Data, Department 1, and Department 2.
In the "Data" worksheet, Column B has a list of all the departments (i.e. Department 1 and Department 2) and Column C has a list of Clients that belong to each department.
The Department 1 and Department 2 worksheets have the exact match formula that's looking up the list of clients based on its department name.
This formula is runs pretty slow even if I'm just looking up 10 clients so I'm wondering if it's possible to speed it up using a macro?
I checked this website and found something that was able to look up 40,000 entries instantly (see below), but it's only running the macro on one worksheet. The real workbook I'm working in has over 30 different departments and I need the formula to run on all 30 worksheets so that the list of clients is unique to the department.
I apologize in advance if the instructions are not as clear, I was hoping I could upload a sample file, but since I'm new here I didn't see an option to upload. Any help is greatly appreciated!
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim vLoookupVal As Variant
Dim vValues As Variant
Dim aResults() As Variant
Dim lResultCount As Long
Dim i As Long
Dim lIndex As Long
Set wb = ActiveWorkbook
Set ws1 = Me 'This is the sheet that contains the lookup value
Set ws2 = wb.Sheets("Sheet2") 'This is the sheet that contains the table of values
Application.EnableEvents = False
If Not Intersect(Target, ws1.Range("A1")) Is Nothing Then
ws1.Columns("B").ClearContents 'Clear previous results
vLoookupVal = Intersect(Target, ws1.Range("A1")).Value
lResultCount = WorksheetFunction.CountIf(ws2.Columns("A"), Target.Value)
If lResultCount = 0 Then
MsgBox "No matches found for [" & vLoookupVal & "]", , "No Matches"
Else
ReDim aResults(1 To lResultCount, 1 To 1)
lIndex = 0
vValues = ws2.Range("A1:B" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row).Value
For i = LBound(vValues, 1) To UBound(vValues, 1)
If vValues(i, 1) = vLoookupVal Then
lIndex = lIndex + 1
aResults(lIndex, 1) = vValues(i, 2)
End If
Next i
ws1.Range("B1").Resize(lResultCount).Value = aResults
End If
End If
Application.EnableEvents = True
End Sub
If I understand you correctly, you want to allocate Client names to the Department sheets which they belong to.
Below code will add the department sheets if they do not exist so you don't have to worry about adding department sheets.
Assuming your department names are in Sheet "Data" Column B, Client Names are in Sheet "Data" Column C, and they both have a header (your data start from 2nd row), and all input data to be inserted into Column A of Department sheets:
Sub MyClients()
Dim lastrow As Long
Dim wsname As String
lastrow = Worksheets("Data").Cells(Worksheets("Data").Rows.Count, 2).End(xlUp).Row
Application.ScreenUpdating = False
For i = 2 To lastrow
wsname = Worksheets("Data").Cells(i, 2).Value
On Error Resume Next
Worksheets(wsname).Cells(Worksheets(wsname).Rows.Count, 1).End(xlUp).Offset(1, 0) = Worksheets("Data").Cells(i, 3).Value
If Err.Number = 9 Then
Sheets.Add(After:=Sheets(Sheets.Count)).Name = Worksheets("Data").Cells(i, 2).Value
Worksheets(wsname).Cells(Worksheets(wsname).Rows.Count, 1).End(xlUp).Offset(1, 0) = Worksheets("Data").Cells(i, 3).Value
End If
Next i
Worksheets("Data").Activate
Application.ScreenUpdating = True
End Sub

MS Excel VBA - Looping through columns and rows

Hello stackoverflow community,
I must confess I primarily code within MS Access and have very limited experience of MS Excel VBA.
My current objective is this, I have an "Expense Report" being sent to me with deductions, this report has many columns with different account names that may be populated or may be null.
My first step will be to start on the first record (Row 14; Column A-K contains personal info regarding the deduction) then skip to the first deduction account (deduction accounts start at column L and span to column DG) checking if each cell is null, if it is then keep moving right,If there is a value present, I need to copy it into an external workbook "Payroll Template" starting at row 2 (Column J for the deduction itself), as well as copy some personal info from the original row in the "Expense Report" related to that deduction (currRow: Column C,E,F from "Expense Report" to "Payroll Template" Columns B,C,D).
Then move to the right until the next cell contains a value, and repeat this process on a new row in the "Payroll Template". Once the last column (DG) has been executed I want to move to the next row (row 15) and start the process again all the way until the "LastRow" in my "Used Range".
I greatly appreciate any feedback, explanations, or links that may point me towards my goal. Thank you in advance for taking the time to read though this!
Current state of code:
`< Sub LoadIntoPayrollTemplate()
Dim rng As Range
Dim currRow As Integer
Dim UsedRng As Range
Dim LastRow As Long
Set UsedRng = ActiveSheet.UsedRange
currRow = 14
Set wb = ActiveWorkbook '"Expense Report"
Set wb2 = MyFilepath '"Payroll Template"
'Copied from another procedure, trying to use as reference
LastRow = rng(rng.Cells.Count).Row
Range("A14").Select
Do Until ActiveCell.Row = LastRow + 1
If (ActiveCell.Value) <> prev Then
currRow = currRow + 1
End If
ActiveCell.Offset(1, 0).Select
Loop
With Worksheets("Collections")
lstRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng = .Range(.Cells(14, 12), Cells(lstRow, 111))
End With
End Sub>`
The following code may do what you are after:
Sub LoadIntoPayrollTemplate()
Dim currRowIn As Long
Dim currColIn As Long
Dim currRowOut As Long
Dim wb As Workbook
Dim wb2 As Workbook
Set wb = ActiveWorkbook '"Expense Report"
Set wb2 = Workbooks.Open(Filename:=MyFilepath & "\" & "Payroll Template.xlsx")
'or perhaps
'Set wb2 = Workbooks.Open(Filename:=wb.path & "\" & "Payroll Template.xlsx")
With wb.ActiveSheet
currRowOut = 1
For currRowIn = 14 To .UsedRange.Row + .UsedRange.Rows.Count - 1
For currColIn = 12 To 111
If Not IsEmpty(.Cells(currRowIn, currColIn)) Then
currRowOut = currRowOut + 1
'I'm not sure which worksheet you want to write the output to
'so I have just written it to the first one in Payroll Template
wb2.Worksheets(1).Cells(currRowOut, "J").Value = .Cells(currRowIn, currColIn).Value
wb2.Worksheets(1).Cells(currRowOut, "B").Value = .Cells(currRowIn, "C").Value
wb2.Worksheets(1).Cells(currRowOut, "C").Value = .Cells(currRowIn, "E").Value
wb2.Worksheets(1).Cells(currRowOut, "D").Value = .Cells(currRowIn, "F").Value
End If
Next
Next
End With
'Save updated Payroll Template
wb2.Save
End Sub

Macros for Auto filter, Auto Copy and then Auto paste in separate sheets

I have the data of the following type in excel:
Year|Trade Flow|Partner|Commodity Code|Commodity|Qty Unit|Qty|Netweight (kg)|Trade Value (US$)
In the year column it ranges from 1990 to 2014. I need to develop a macro code such that it can filter the values based on year individually and then paste it in different sheets of the same excel file.
Any help in this regard,. would be great.
Thanks.
Loop through the rows. Each time you hit a new year, insert a sheet for that year and copy the rows to it.
This assumes your data is on sheet1 and you don't have sheets named 1990, 1991, 1992, etc.
This also assumes that your data is sorted by ColumnA(Year).
Private Sub CommandButton1_Click()
Dim ws As Excel.Worksheet
Dim strValue As String
Set ws = ActiveWorkbook.Sheets("Sheet1")
Dim jRow As Long
Dim lRow As Long
lRow = 1
jRow = 1
ws.Activate
'Loop through and copy the records to the new sheet.
Do While lRow <= ws.UsedRange.Rows.count
'If this is a new year, create a sheet for it.
If ws.Range("A" & lRow).Value <> strValue Then
strValue = ws.Range("A" & lRow).Value
Worksheets.Add(After:=Worksheets(Worksheets.count)).name = strValue
jRow = 1
End If
ws.Rows(lRow).Copy Destination:=Worksheets(strValue).Range("A" & jRow)
jRow = jRow + 1
lRow = lRow + 1
Loop
End Sub

Merge specific sheets by adding the sheet name as the first column

I have quite a number of sheets whose names end in _A or _B.
I would like to merge all sheets ending in _A or _B under one another. They have the same number of columns, but different number of rows. However, when merging, I want the sheetname to be repeated all the way down the last row of that sheet in the merged sheet. Result:
I want the results to be saved in the same workbook but in a sheet called "merged".
here is the example sheet if you would like to work on.
what I have tried:
Sub Merge_into_One()
Dim ws As Worksheet
Dim TargetRow As Long
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
TargetRow = 1
For Each ws In ActiveWorkbook.Sheets
With ws
If .Name Like "*" & strSearch & "_A" Or _
.Name Like "*" & strSearch & "_B" Then
.Range("A1:C99").Copy
With Worksheets("Merged").Cells(TargetRow, 1)
.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
End With
TargetRow = TargetRow + 99
End If
End With
Next ws
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
But here, i am taking 99 rows, supposing that my rows will not exceed this number. However, I want to take exactly the same number of rows that appear in each sheet, not more not less. And here I cannot put the name of the sheet in the first column and repeat it until the last hit of the same sheet.
Not tested. EDIT: Oops I forgot a few things it seems.
dim RowsToMerge as integer
dim RowsPresent
dim RangeToMerge as range
For i = 1 To ActiveWorkbook.Worksheets.Count
If Instr(Worksheets(i).Name, "ABC") <> 0 Then
Set ws = Worksheets(i)
RowsToMerge = ws.Cells(Rows.Count, "A").End(xlUp).Row
RowsPresent = Sheets("Merged").Cells(Rows.Count, "A").End(xlUp).Row
Set RangeToMerge = ws.Range("A1:C" & RowsToMerge)
ws.RangeToMerge.Copy destination:=Worksheets("Merged").Range("B" & RowsPresent + 1)
Worksheets("Merged").Range("A" & RowsPresent + 1) = ws.Name
End If
Next