I have an Excel workbook which contains n sheets. I want to merge the data from each sheet to one single sheet. The header and data from the first sheet should be on top, the data from second sheet should be below it and so on. All the sheets have the same columns and headers structure. So, the header should appear only once i.e take header and data from first sheet and only data from remaining sheets. I have the following code:
Sub Combine()
'This macro will copy all rows from the first sheet
'(including headers)
'and on the next sheets will copy only the data
'(starting on row 2)
Dim i As Integer
Dim j As Long
Dim SheetCnt As Integer
Dim lstRow1 As Long
Dim lstRow2 As Long
Dim lstCol As Integer
Dim ws1 As Worksheet
With Application
.DisplayAlerts = False
.EnableEvents = False
.ScreenUpdating = False
End With
On Error Resume Next
'Delete the Target Sheet on the document (in case it exists)
Sheets("Target").Delete
'Count the number of sheets on the Workbook
SheetCnt = Worksheets.Count
'Add the Target Sheet
Sheets.Add after:=Worksheets(SheetCnt)
ActiveSheet.Name = "Target"
Set ws1 = Sheets("Target")
lstRow2 = 1
'Define the row where to start copying
'(first sheet will be row 1 to include headers)
j = 1
'Combine the sheets
For i = 1 To SheetCnt
Worksheets(i).Select
'check what is the last column with data
lstCol = ActiveSheet.Cells(1, ActiveSheet.Columns.Count).End(xlToLeft).Column
'check what is the last row with data
lstRow1 = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
'Define the range to copy
Range("A2:G2" & j, Cells(lstRow1, lstCol)).Select
'Copy the data
Selection.Copy
ws1.Range("A2:G2" & lstRow2).PasteSpecial
Application.CutCopyMode = False
Selection.Offset(1, 0).Resize(Selection.Rows.Count - 1).Select
'Define the new last row on the Target sheet
lstRow2 = ws1.Cells(65535, "A").End(xlUp).Row + 1
'Define the row where to start copying
'(2nd sheet onwards will be row 2 to only get data)
j = 3
Next
With Application
.DisplayAlerts = True
.EnableEvents = True
.ScreenUpdating = True
End With
Sheets("Target").Select
Cells.EntireColumn.AutoFit
Range("A1").Select
End Sub
With this code, my data from all sheets is getting overlapped. I want the data to be one below the other.
It's overlapping because you don't increment the paste area on the Target sheet
To fix the problem offset the paste area correspondingly:
Sheet 1: copy 10 rows-paste -> increment paste start & end area by 10
Sheet 2: copy 15 rows-paste -> increment paste start & end area by 25: 10 + 15 and so on...
You can also replace this:
Sheets.Add after:=Worksheets(SheetCnt) 'Add the Target Sheet
ActiveSheet.Name = "Target"
Set ws1 = Sheets("Target")
with this:
Set ws1 = Sheets.Add(after:=Worksheets(SheetCnt)) 'Add the Target Sheet
ws1.Name = "Target"
If you eliminate all "Select" statements and refer to each object explicitly it will allow you to reduce code, and un-needed complexity
Here is my version:
Option Explicit
Public Sub Combine()
Const HEADR As Byte = 1
Dim i As Long, rngCurrent As Range
Dim ws As Worksheet, wsTarget As Worksheet
Dim lCol As Long, lCel As Range
Dim lRow As Long, toLRow As Long
With Application
.DisplayAlerts = False
.EnableEvents = False
.ScreenUpdating = False
End With
For Each ws In Worksheets 'Delete Target Sheet if it exists
With ws
If .Name = "Target" Then
.Delete
Exit For
End If
End With
Next
Set wsTarget = Worksheets.Add(After:=Worksheets(Worksheets.Count))
wsTarget.Name = "Target"
Set lCel = GetMaxCell(Worksheets(1).UsedRange)
If lCel.Row > 1 Then
With Worksheets(1)
'Expected: all sheets will have the same number of columns
lCol = lCel.Column
lRow = HEADR
toLRow = HEADR
.Range(.Cells(HEADR, 1), .Cells(HEADR, lCol)).Copy
With wsTarget
.Range(.Cells(HEADR, 1), .Cells(HEADR, lCol)).PasteSpecial xlPasteAll
End With
End With
For i = 1 To Worksheets.Count 'concatenate data ---------------------------
Set lCel = GetMaxCell(Worksheets(i).UsedRange)
If lCel.Row > 1 Then
With Worksheets(i)
If .Name <> "Target" Then 'exclude the Target
toLRow = toLRow + lRow 'last row on Target
lRow = lCel.Row 'last row on current
Set rngCurrent = .Range(.Cells(HEADR + 1, 1), _
.Cells(lRow, lCol))
lRow = lRow - HEADR
With wsTarget
.Range(.Cells(toLRow, 1), _
.Cells(toLRow + (lRow - HEADR), lCol)) = _
rngCurrent.Value
End With
End If
End With
End If
Next '--------------------------------------------------------------------
With wsTarget
.Columns.AutoFit
.Range("A1").Select
End With
With Application
.CutCopyMode = False
.DisplayAlerts = True
.EnableEvents = True
.ScreenUpdating = True
End With
End If
End Sub
Public Function GetMaxCell(Optional ByRef rng As Range = Nothing) As Range
'Returns the last cell containing a value, or A1 if Worksheet is empty
Const NONEMPTY As String = "*"
Dim lRow As Range, lCol As Range
If rng Is Nothing Then Set rng = Application.ActiveWorkbook.ActiveSheet.UsedRange
If WorksheetFunction.CountA(rng) = 0 Then
Set GetMaxCell = rng.Parent.Cells(1, 1)
Else
With rng
Set lRow = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _
After:=.Cells(1, 1), _
SearchDirection:=xlPrevious, _
SearchOrder:=xlByRows)
If Not lRow Is Nothing Then
Set lCol = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _
After:=.Cells(1, 1), _
SearchDirection:=xlPrevious, _
SearchOrder:=xlByColumns)
Set GetMaxCell = .Parent.Cells(lRow.Row, lCol.Column)
End If
End With
End If
End Function
'--------------------------------------------------------------------------------------
Offsetting the paste area is done by incrementing lRow and toLRow
Edit:
If you use this code and you want to transfer cell formatting for all data cells replace this section:
'copy data to Target sheet
With wsTarget
.Range(.Cells(toLRow, 1), .Cells(toLRow + (lRow - HEADR), lCol)) = _
rngCurrent.Value
End With
with this:
'copy data to Target sheet
rngCurrent.Copy
With wsTarget
With .Range(.Cells(toLRow, 1), .Cells(toLRow + (lRow - HEADR), lCol))
.PasteSpecial xlPasteAll
End With
End With
but it will become slower if you're processing a lot of sheets
EDIT: to show how to handle special cases
The above solution is more generic and dynamically detects the last column and row containing data
The number of columns (and rows) to be processed can be manually updated. For example, if your sheets contain 43 columns with data, and you want to exclude the last 2 columns, make the following change to the script:
Line
Set lCel = GetMaxCell(Worksheets(1).UsedRange)
changes to
Set lCel = Worksheets(1).UsedRange("D41")
Related
I am currently new to macro VBA and I have been trying to copy a column if the values of a specific rows are the same then paste it on another sheet until all columns are copied and pasted. The purpose of this is to consolidate team members of a team (the team is the value that im trying to look for). It only stops when the next cell to the right is already blank. And I will only find the team members' team on the first row of the sheet only. I placed a code that I found on the Internet and modified it but it only copies the last DATA team it finds. Thank you.
Dim ws As Worksheet
Dim aCell As Range, Rng As Range
Dim col As Long, lRow As Long
Dim colName As String
Set ws = ThisWorkbook.Sheets("Values")
With ws
Set aCell = .Range("A1:XFD1").Find(What:="DATA", LookIn:=xlValues, LookAt:=xlWhole, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
aCell.EntireColumn.Cut
Sheets("Team").Columns("D:W").Insert Shift:=xlToRight
Else
MsgBox "Team not found"
End If
End With
You can try this.
Option Explicit
Sub CopyCols()
Dim ArrTeams() As String, Team As String
Dim TeamCounter As Long, LastCol As Long, FirstCol As Long, i As Long, LastColDest As Long
Dim SrcWs As Worksheet
Dim Wb As Workbook
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set Wb = ThisWorkbook
Set SrcWs = Wb.Sheets("Sheet1")
ReDim ArrTeams(1 To 1)
With Wb
With SrcWs
'find last column with team
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
TeamCounter = 1
FirstCol = 1 'or whatever your first column with teams is
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
If Not IsInArray(Team, ArrTeams) Then 'take only unique team names
ReDim Preserve ArrTeams(1 To TeamCounter)
ArrTeams(TeamCounter) = Team
TeamCounter = TeamCounter + 1
End If
End If
Next i
End With
'create new sheet for each team
For i = 1 To UBound(ArrTeams)
.Sheets.Add after:=.Sheets(.Sheets.Count)
.Sheets.Item(.Sheets.Count).Name = ArrTeams(i)
Next i
With SrcWs
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
With Wb.Sheets(Team)
'find last non empty column on destination sheet
LastColDest = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
.Cells(1, i).EntireColumn.Copy
Wb.Sheets(Team).Cells(1, LastColDest + 1).PasteSpecial
End If
Next i
End With
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
It should loop all columns on "Sheet1" starting in FirstCol and ending in LastCol, take unique team names from first row. Create new sheet for each unique team name. Copy entire column for each unique team name to coresponding sheet.
Just remember that it will allways add new sheets so if you want to run it multiple times then there should be check if sheet with specific name already exists.
EDIT
Add
Dim LastRow As Long, j As Long
And
Dim TargetWs As Worksheet
in declaration part at begining
Change loop for adding new sheets to
For i = 1 To UBound(ArrTeams)
.Sheets.Add after:=.Sheets(.Sheets.Count)
.Sheets.Item(.Sheets.Count).Name = ArrTeams(i)
.Sheets(ArrTeams(i)).Range("A2:A1000").FormulaR1C1 = _
"=SUM(RC[2]:RC[" & .Sheets(ArrTeams(i)).Columns.Count - 1 & "])"
Next i
at the end add
For i = LBound(ArrTeams) To UBound(ArrTeams)
Team = ArrTeams(i) 'team name and also sheet name
Set TargetWs = .Sheets(Team)
With TargetWs
.Calculate 'calculate SUM formula on each sheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row with data in column "A"
For j = LastRow To 2 Step -1 'assuming that in row 1 there is some header
If .Cells(j, "A") = 0 Then
.Cells(j, "A").EntireRow.Delete
End If
Next j
End With
Next i
This should do the trick as long as you don't have more than 1000 rows of data. If so you can adjust SUM formula to cover more rows or find last row with data on each "Team" sheet and adjust formula in loop.
Hi #Sphinx this is what I have so far. And I modified the code you have given and added something to it. The syntax that I do not have is on how to delete a row when a specific cell on column C has 0 value. And it should work on all ArrTeams(i) sheets only. Thank you for you help.
https://i.stack.imgur.com/M8NS8.png
Option Explicit
Sub CopyCols()
Dim ArrTeams() As String, Team As String
Dim TeamCounter As Long, LastCol As Long, FirstCol As Long, i As Long, LastColDest As Long
Dim SrcWs As Worksheet
Dim Wb As Workbook
Dim LastRowColumnD As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set Wb = ThisWorkbook
Set SrcWs = Wb.Sheets("Values")
ReDim ArrTeams(1 To 1)
With Wb
With SrcWs
'find last column with team
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
TeamCounter = 1
FirstCol = 1 'or whatever your first column with teams is
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
If Not IsInArray(Team, ArrTeams) Then 'take only unique team names
ReDim Preserve ArrTeams(1 To TeamCounter)
ArrTeams(TeamCounter) = Team
TeamCounter = TeamCounter + 1
End If
End If
Next i
End With
'create new sheet for each team
For i = 1 To UBound(ArrTeams)
.Sheets.Add After:=.Sheets(.Sheets.Count)
.Sheets.Item(.Sheets.Count).Name = ArrTeams(i)
Sheets("Values").Columns("A:C").Copy
ActiveSheet.Paste Destination:=Worksheets(ArrTeams(i)).Range("A1:C1")
Range("A1").Value = " "
Range("B1").Value = " "
Range("C1").Value = " "
Range("A2").Value = "Team:"
Range("B2").Value = ArrTeams(i)
Range("C2").Value = " "
Range("B2").HorizontalAlignment = xlCenter
Range("B2").VerticalAlignment = xlCenter
Range("A2").HorizontalAlignment = xlCenter
Range("A2").VerticalAlignment = xlCenter
LastRowColumnD = Cells(Rows.Count, 1).End(xlUp).Row
Range("C4:C" & LastRowColumnD).Formula = "=sum(D4:XFD4)"
Next i
With SrcWs
'loop all columns in row 1
For i = FirstCol To LastCol
If .Cells(1, i) <> "" Then
Team = .Cells(1, i)
With Wb.Sheets(Team)
'find last non empty column on destination sheet
LastColDest = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
.Cells(1, i).EntireColumn.Copy
Wb.Sheets(Team).Cells(1, LastColDest + 1).PasteSpecial
End If
Next i
End With
End With
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
I would like to have a macro that can read the values of a table, and copy the rows to a respective names worksheet if it match.
Lets say I have a template and Sheet1 worksheets. (unable to embed image yet)
Sheet1 Table
'template' worksheet is the source where if column F value match one of the ID in Sheet1, it will be copied to the respective group(worksheet)
Example - all rows that contain 123 in column F of template will be copied to 'North' worksheet.
I have modified parts of the code provided from the excel masters here.
However it is throwing a error 'Object variable or With Block variable not set' at this code UpdateWs ws(wsTosaveto), ur
Any help would be appreciated..
Sub sliceNdice()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Const master_ws As String = "template"
Const master_col As String = "F" 'AutoFilter column in Master sheet
Dim OldBook As Workbook
Dim LastRow As Long, i As Long
Dim valuetoFind As String, wsTosaveto As String
Dim ws As Worksheet, lr As Long, lc As Long, ur As Range, fCol As Range, done As Range
Dim wb As Workbook
Set wb = Application.ThisWorkbook
With wb.Worksheets(master_ws)
lr = .Cells(.Rows.Count, master_col).End(xlUp).Row 'find last row of template
lc = .Cells(1, .Columns.Count).End(xlToLeft).Column 'find last column template
Set ur = .Range(.Cells(3, 1), .Cells(lr, lc)) 'set the range of data
Set fCol = .Range(.Cells(2, master_col), .Cells(lr, master_col))
Set done = .Range(.Cells(1, master_col), .Cells(2, master_col))
End With
Set OldBook = ThisWorkbook
'Find last row of Sheet1 table
LastRow = OldBook.Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
'Scan all rows of Sheet1 table
For i = 3 To LastRow 'Start in third row. First 2 row for titles
valuetoFind = OldBook.Worksheets("Sheet1").Cells(i, 1).Value
wsTosaveto = OldBook.Worksheets("Sheet1").Cells(i, 2).Value
fCol.AutoFilter Field:=1, Criteria1:=valuetoFind
If fCol.SpecialCells(xlCellTypeVisible).Cells.Count > 1 Then
UpdateWs ws(wsTosaveto), ur
Set done = Union(done, fCol.SpecialCells(xlCellTypeVisible))
End If
Next i
If wb.Worksheets(master_ws).AutoFilterMode Then
fCol.AutoFilter
UpdateNA done, ur
End If
Application.ScreenUpdating = True
End Sub
Private Sub UpdateWs(ByRef ws As Worksheet, ByRef fromRng As Range)
fromRng.Copy
With ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(1, 0)
.PasteSpecial xlPasteAll
End With
ws.Activate
ws.Cells(1).Select
End Sub
Private Sub UpdateNA(ByRef done As Range, ByRef ur As Range)
done.EntireRow.Hidden = True
If ur.SpecialCells(xlCellTypeVisible).Cells.Count > 1 Then
UpdateWs ThisWorkbook.Worksheets(NA_WS), ur.SpecialCells(xlCellTypeVisible)
End If
done.EntireRow.Hidden = False
Application.CutCopyMode = False
ur.Parent.Activate
End Sub
I have multiple sheets, each with data only in the first two columns:
Column A - ID
Column B - Name
I am trying to consolidate all these sheets into a master sheet. The format of the master sheet should be:
Column A - Sheet Name (From where the data was copied)
Column B - ID
Column C - Name
I have found a site that has code that does more or less this, however, after messing around with it for what feels like an eternity I just cannot get it to work.
The code works, in the sense that it copies the correct range and inputs the sheet name into column A, however, it doesn't stop by the "last row" of the range in the master sheet, it continues to populate the ENTIRE column A and the IF Statement that counts the rows is triggered and I get the msgbox pop up (see below in code). At this point, the code just ends and it does not get a chance to execute for the remaining sheets.
Link to site: https://www.rondebruin.nl/win/s3/win002.htm
Below is the code from the original site, with some minor adjustments for the range I will be using:
Sub CopySheetNameToColumn()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the sheet "RDBMergeSheet" if it exist
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add a worksheet with the name "RDBMergeSheet"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the last row with data on the DestSh
Last = LastRow(DestSh)
'Fill in the range that you want to copy
Set CopyRng = sh.Range("A:B")
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng.Rows.count > DestSh.Rows.count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
End If
'This example copies values/formats, if you only want to copy the
'values or want to copy everything look at the example below this macro
CopyRng.Copy
With DestSh.Cells(Last + 1, "B")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
'Optional: This will copy the sheet name in the H column
DestSh.Cells(Last + 1, "A").Resize(CopyRng.Rows.count).Value = sh.Name
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Functions:
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Function LastCol(sh As Worksheet)
On Error Resume Next
LastCol = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
End Function
Instead of
Set CopyRng = sh.Range("A:B")
try
Set CopyRng = sh.Range("A1", sh.Range("B" & Rows.Count).End(xlUp))
as the former covers every row of the worksheet, hence the message box and the name running down the whole sheet.
Something like:
Option Explicit
Sub CopySheetNameToColumn()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
Last = GetLastRow(DestSh, 1)
With sh
Set CopyRng = sh.Range("A1:B" & GetLastRow(sh, 1))
End With
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
Else
CopyRng.Copy IIf(Last = 1, DestSh.Cells(1, "B"), DestSh.Cells(Last + 1, "B"))
End If
If Last = 1 Then
DestSh.Cells(Last, "A").Resize(CopyRng.Rows.Count).Value = sh.Name
Else
DestSh.Cells(Last + 1, "A").Resize(CopyRng.Rows.Count).Value = sh.Name
End If
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Public Function GetLastRow(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1) As Long
With ws
GetLastRow = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function
You can shorten this significantly... there are lots of posts about getting items on a master sheet, 4 from yesterday alone.
Take a look at this:
Dim lrSrc As Long, lrDst As Long, i As Long
For i = 1 To Sheets.Count
If Not Sheets(i).Name = "Destination" Then
lrSrc = Sheets(i).Cells(Sheets(i).Rows.Count, "A").End(xlUp).Row
lrDst = Sheets("Destination").Cells(Sheets("Destination").Rows.Count, "A").End(xlUp).Row
With Sheets(i)
.Range(.Cells(2, "A"), .Cells(lrSrc, "B")).Copy Sheets("Destination").Range(Sheets("Destination").Cells(lrDst + 1, "B"), Sheets("Destination").Cells(lrDst + 1 + lrSrc, "C")) 'Assumes headers in first row aren't being copied
Sheets("Destination").Range(Sheets("Destination").Cells(lrDst + 1, "A"), Sheets("Destination").Cells(lrDst + 1 + lrSrc, "A")).Value = Sheets(i).Name
End With
End If
Next i
Code now tested
I'm trying to add a vba code that looks in a column on sheet YTDFigures and sees if there is a duplicate in sheet EeeDetails. If there isn't then I want to copy the YTDFigures data and paste in a new sheet.
The code I've tried gets an error run time error 91 on the line FinName = Worksheets("EeeDetails").Range("A:A").Find(What:=SearchName, LookIn:=xlValues) I thought this would work as if a match isn't found the .Find function returns nothing.
Sub CheckMatch()
Application.ScreenUpdating = False
Dim SearchName As Range, SearchNames As Range
Dim Usdrws As Long
Dim row As Integer
Usdrws = Worksheets("YTDFigures").Range("A" & Rows.Count).End(xlUp).row
Set SearchNames = Worksheets("YTDFigures").Range("A2:A" & Usdrws)
For Each SearchName In SearchNames
row = Split(SearchName.Address, "$")(2)
FinName = Worksheets("EeeDetails").Range("A:A").Find(What:=SearchName, LookIn:=xlValues)
If FinName Is Nothing Then
Range("A" & row & ":S" & row).Copy
LastRow = Worksheets("Errors").Range("AA" & Rows.Count).End(xlUp).row + 1
Worksheets("Errors").Activate
Range("A" & LastRow).Select
Selection.PasteSpecial
Worksheets("EeeDetails").Activate
End If
Next
Application.ScreenUpdating = True
End Sub
You can place the raw data into an array, place the array on a temporary sheet, remove the duplicates, copy the data, then delete the temp sheet.
See below:
Sub CheckMatch()
Application.ScreenUpdating = False
Dim ws As Worksheet, tRows As Long
Set ws = ThisWorkbook.Worksheets(1)
Set RngA = ws.UsedRange.Columns("A")
tRows = ws.Rows(ws.Rows.Count).End(xlUp).row
Dim valA As Variant
valA = ws.Range(ws.Cells(1, 1), ws.Cells(tRows, 1)).Value
Dim tempWs As Worksheet
Set tempWs = ThisWorkbook.Worksheets.Add
tempWs.Name = "Temp1"
With tempWs
.Range(.Cells(1, 1), .Cells(tRows, 1)) = valA
With .UsedRange.Columns("A")
.RemoveDuplicates Columns:=1, Header:=xlYes
.Copy
End With
End With
' Do what you need to do with your copied data
Application.DisplayAlerts = False
tempWs.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Edit:
I just tested this with sample data of over 10k rows, and it works in less than a half a second. It's very fast.
I am trying to copy cell values that meet two conditions: (1) highlighted row, and (2) have a particular region code, e.g. "WA". Need to copy cell values from column B to the destination worksheet below the header in column A. In addition, copy the sheet name that corresponds to those values that meet those conditions to column C to the destination worksheet.
Problems I have encountered:
As soon as I add this code it runs but doesn't past any values to the destination sheet. LCase(Cells(Cell.Row, "A").Value) = "wa"
If I remove the line of code above, and change the target area to look in column 2 Set Target = .Range(.Cells(1, 2), .Cells(LastRow, 2)), it will list the values that are highlighted in column B and paste them down starting on A1, instead of starting below the header.
Partial Target Area (full target area has different region codes and values going down these columns):
Sub Criteria()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wkb As Workbook
Dim Sh As Worksheet
Dim DestSh As Worksheet
Dim LastRow As Long, LastCol As Long, Last As Long
Dim Target As Range, Cell As Range, Dest As Range
Dim DestCounter As Long
' Delete the data off of AdvFilter sheet.
ActiveWorkbook.Worksheets("AdvFilter").Range("A5:F5" & Last + 1).Cells.Clear
On Error GoTo 0
'initialize destination counter
DestCounter = 1
Set DestSh = ThisWorkbook.Worksheets("AdvFilter")
For Each Sh In ThisWorkbook.Worksheets
If ActiveSheet.Visible = True Then
Last = fLastRow(DestSh)
With Sh
LastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Set Target = .Range(.Cells(1, 1), .Cells(LastRow, 2))
End With
For Each Cell In Target '<~ loop through each cell in the target space
If AmIYellow(Cell) And Cell.Value <> "" And _
LCase(Cells(Cell.Row, "A").Value) = "wa" Then
Set Dest = DestSh.Cells(Last + DestCounter, 1)
Cell.Copy Dest
DestCounter = DestCounter + 1
End If
Next Cell
End If
Next Sh
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Function fLastRow(Sh As Worksheet)
On Error Resume Next
LastRow = Sh.Cells.Find(What:="*", _
After:=Sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
If you only need the data and not the formatting; you'll be better off using an array to collect the data and write all the data in one operation to the target range.
Sub Criteria()
Dim ws As Worksheet
Dim r As Range
Dim x As Long
Dim Data
ReDim Data(1 To 2, 1 To 1)
With ActiveWorkbook.Worksheets("AdvFilter")
.Range(.Range("A" & .Rows.Count).End(xlUp), "F5").Cells.Clear
End With
For Each ws In ThisWorkbook.Worksheets
If ws.Visible = xlSheetVisible Then
With ws
For Each r In .Range("A2", .Range("A" & .Rows.Count).End(xlUp))
If LCase(r.Value) = "wa" And r.Interior.ColorIndex = 6 Then
x = x + 1
ReDim Preserve Data(1 To 2, 1 To x)
Data(1, x) = r.Offset(0, 1)
Data(2, x) = ws.Name
End If
Next
End With
End If
Next
With ActiveWorkbook.Worksheets("AdvFilter")
With .Range("A" & .Rows.Count).End(xlUp).Offset(1)
If x > 0 Then .Resize(x, 2).Value = Application.Transpose(Data)
End With
End With
End Sub