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
Related
I have this Macro which essentially uses two sheets - sheet2 updates sheet1 and then kills the second worksheet.
I noticed that when it comes to one part of the macro (delete row which has "Delete" in column A in worksheet 1) it doesn't appear to work if I run the Macro from worksheet 2. If I run it from Sheet 1 is works without a problem.
This is the full code, just in case you need to look at it - I'll highlight the part that I'm having trouble with next.:
Public Sub Cable_Load_full()
'~~> Copy New Accounts from worksheet2
Dim ws1 As Worksheet, ws2 As Worksheet
Dim bottomL As Integer
Dim x As Integer
Dim c As Range
Dim i As Long, J As Long, LastCol As Long
Dim ws1LR As Long, ws2LR As Long
Dim ws1Rng As Range, aCell As Range
Dim SearchString
Set ws1 = Sheets("CableSocials")
Set ws2 = Sheets("CableRevised")
bottomL = ws2.Range("A" & Rows.Count).End(xlUp).Row: x = 1
x = ws1.Range("A" & Rows.Count).End(xlUp).Row
x = x + 1
For Each c In ws2.Range("A1:A" & bottomL)
If c.Value = "New" Then
c.EntireRow.Copy ws1.Range("A" & x)
x = x + 1
End If
Next c
'~~> Assuming that ID is in Col B
'~~> Get last row in Col B in Sheet1
ws1LR = ws1.Range("B" & Rows.Count).End(xlUp).Row
'~~> Set the Search Range
Set ws1Rng = ws1.Range("B1:B" & ws1LR)
'~~> Adding Revise Column to worksheet 1
ws1.Columns("A:A").Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("A1").Value = "Revise"
Set ws2 = Sheets("CableRevised")
'~~> Turn off Filter
ws2.AutoFilterMode = False
'~~> Get last row in Col A in Sheet2
ws2LR = ws2.Range("B" & Rows.Count).End(xlUp).Row
'~~> Loop through the range in Sheet 2 to match it with the range in Sheet1
For i = 1 To ws2LR
SearchString = ws2.Range("B" & i).Value
'~~> Search for the ID
Set aCell = ws1Rng.Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'~~> If found
If Not aCell Is Nothing Then
'~~> Append values
ws1.Cells(aCell.Row, 1).Value = ws2.Cells(i, 1).Value
ws1.Cells(aCell.Row, 3).Value = ws2.Cells(i, 2).Value
ws1.Cells(aCell.Row, 19).Value = ws2.Cells(i, 18).Value
ws1.Cells(aCell.Row, 20).Value = ws2.Cells(i, 19).Value
End If
Next i
'~~> Delete the accounts that need to be deleted
ws1.AutoFilterMode = False
With Range("A1", Range("A" & Rows.Count).End(xlUp))
.AutoFilter 1, "Delete"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
ws1.AutoFilterMode = False
'~~> Removing New from Column B
ws1.Columns("B").Replace What:="New", _
Replacement:="", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
ws1.Columns("A").EntireColumn.Delete
Call SheetKiller
End Sub
Sub SheetKiller()
Dim s As Worksheet, t As String
Dim i As Long, K As Long
K = Sheets.Count
For i = K To 1 Step -1
t = Sheets(i).Name
If t = "CableRevised" Then
Application.DisplayAlerts = False
Sheets(i).Delete
Application.DisplayAlerts = True
End If
Next i
End Sub
So the part that only works when I run the Macro from Sheet1 is:
'~~> Delete the accounts that need to be deleted
ws1.AutoFilterMode = False
With Range("A1", Range("A" & Rows.Count).End(xlUp))
.AutoFilter 1, "Delete"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
ws1.AutoFilterMode = False
I'm not sure why - is it acting as if it will only delete the rows from the ActiveSheet (which I guess would be the Sheet I run the Macro from?) ? Is it possible to make it work even if I run the Macro from Sheet2?
Thanks for any help you provide!
You need to explicitly refer to ranges on ws1. As written, your code is looking for ranges on the active sheet.
Try this:
'~~> Delete the accounts that need to be deleted
ws1.AutoFilterMode = False
With ws1.Range("A1", ws1.Range("A" & ws1.Rows.Count).End(xlUp))
.AutoFilter 1, "Delete"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
ws1.AutoFilterMode = False
I'm trying to find a solution to a second part of the code.
I have a table with 5 columns containing about 70 records (every time different number) and I need to create new spreadsheets (each tab is named as a record number in the first column) for each record where values for other records in the first two columns will be hidden(removed/deleted). The first row and the last row of the table shouldn't be hidden as they contain columns' headers and Total formulas (5th column contains formulas as well).
I've managed to create a code to solve the first part of the problem of creating spreadsheets with all data and changing names for those tabs. But I still cannot figure out how to keep only values for one record in a spreadsheet and hide/remove/delete values in the first two columns for other records.
Here is the code I have, would be grateful for any help!
Sub Create()
Dim I As Long
Dim xNumber As Integer
Dim xName As String
Dim ws As Worksheet
Dim rg As Range
Dim lastRow As Long
On Error Resume Next
Application.ScreenUpdating = False
Set ws = ActiveSheet
lastRow = ws.Range("B" & ws.Rows.Count).End(xlUp - 1).Row
Set rg = Range("A1:A" & lastRow)
xNumber = InputBox("Enter number of times to copy the current sheet")
For I = 1 To xNumber
xName = ActiveSheet.Name
ws.Copy After:=ActiveWorkbook.Sheets(xName)
ActiveSheet.Name = ws.Range("A" & I + 1).Value
With rg
.AutoFilter Field:=1, Criteria1:=ActiveSheet.Name
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireColumn.Clear
End With
Next
ws.Activate
Application.ScreenUpdating = True
End Sub
Here is an answer with some code that will:
Loop through all your sheets
Looking for current sheet name (If not there then do nothing)
Delete/clear cells untill there is just the 3 rows left
Adjust to your liking
Sub DoStuff1()
Dim WS As Worksheet
Dim LR As Long, FR As Long
Dim CL As Range
Application.ScreenUpdating = False 'Turn the screen refresh off
For Each WS In ThisWorkbook.Sheets 'Loop through your sheets
WS.Activate
StartHere: LR = WS.Cells(Rows.Count, "A").End(xlUp).Row - 1 'Get the dynamic last used row
Set CL = WS.Columns(1).Find(What:=WS.Name, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not CL Is Nothing Then
FR = CL.Row 'Get the row which is the value
If FR > 2 And FR < LR Then 'If larger than 2 but smaller than last used row then
WS.Range(Cells(2, 1), Cells(FR - 1, 2)).Delete Shift:=xlUp
GoTo StartHere
ElseIf FR = 2 And FR < LR Then 'If FR = 2 but still some rows between FR and LR
WS.Range(Cells(FR + 1, 1), Cells(LR, 2)).Delete Shift:=xlUp
GoTo StartHere
ElseIf FR = LR And FR > 2 Then 'If A is the lastrow with a value but rows between 2 and FR
WS.Range(Cells(2, 1), Cells(FR - 1, 2)).Delete Shift:=xlUp
GoTo StartHere
Else
'If there is only the startrow, the foundrow with value and the very last row left...
End If
End If
Next WS
Application.ScreenUpdating = True 'Turn the screen refresh back on
End Sub
EDIT: Second option, clearing cells instead of deleting
Sub DoStuff2()
Dim WS As Worksheet
Dim LR As Long, FR As Long
Dim CL As Range
Application.ScreenUpdating = False
For Each WS In ThisWorkbook.Sheets
WS.Activate
LR = WS.Cells(Rows.Count, "A").End(xlUp).Row - 1
Set CL = WS.Columns(1).Find(What:=WS.Name, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not CL Is Nothing Then
FR = CL.Row
If FR > 2 And FR < LR Then WS.Range(Cells(2, 1), Cells(FR - 1, 2)).ClearContents
If FR < LR And FR > 2 Then WS.Range(Cells(FR + 1, 1), Cells(LR, 2)).ClearContents
If FR = 2 And FR < LR Then WS.Range(Cells(FR + 1, 1), Cells(LR, 2)).ClearContents
If FR = LR And FR > 2 Then WS.Range(Cells(2, 1), Cells(FR - 1, 2)).ClearContents
End If
Next WS
Application.ScreenUpdating = True
End Sub
I created a macro that fills the missing Data with specific Data from another sheet , the codes works perfectly in copying pasting data from excel of the client and prepare the data needed to start the work but the only problem here below
Code:
With Worksheets("Feuil2")
' reference "target" sheet (change "Target" to our actual target sheet name)
With .Range("B1:B" & .Cells(.Rows.Count, 1).End(xlUp).Row) 'reference
its column B range from row 1 down to last not empty one
If WorksheetFunction.CountBlank(.Cells) > 0 Then
' if any blank cell in referenced range. this check to avoid error thrown by subsequent
statament
.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=index(GDC!" & rng.Offset(, 1).Address(, , xlR1C1) & ",match(RC[-1],GDC!" & rng.Address(, , xlR1C1) & ",0))" 'fill blank cells with a lookup (well, sort of) formula
.Value = .Value 'get rid of formulas and leave values only
Cells.Select
End If
End With
End With
This code works perfectly in matching and filling data but when for e.g find a duplicated value it copy only the first value not the second one
See the image below to better understand the main problem :
As you can see in the image The problem that in column A i may have data repeated twice like this value P20845 which in column F it is repeated one with the name of Ghaith and the other with the name of sirine but as you can see in the column A it is just with the name also of Ghaith and there is no name of sirine
Anyidea or better solution in solving this and getting all the needed DATA? .
Best Regards
POLOS
Or use a dictionary
Option Explicit
Public Sub AddValues()
Application.ScreenUpdating = False
Dim wb As Workbook, wsSource As Worksheet, wsTarget As Worksheet, masterDict As Object, arr() As Variant, i As Long, rng As Range
Set wb = ThisWorkbook
Set wsSource = wb.Worksheets("Feuil1")
Set wsTarget = wb.Worksheets("Feuil2")
Set masterDict = CreateObject("Scripting.Dictionary")
With wsSource
arr = Intersect(.Columns("A:B"), .UsedRange)
For i = 1 To UBound(arr, 1)
If Not masterDict.exists(arr(i, 1)) Then masterDict.Add arr(i, 1), GetAllMatches(arr(i, 1), arr(i, 2), wsSource)
Next i
End With
With wsTarget
For Each rng In Intersect(.Columns("A"), .UsedRange)
On Error Resume Next
rng.Offset(, 1) = masterDict(rng.Value)
On Error GoTo 0
Next rng
End With
Application.ScreenUpdating = True
End Sub
Public Function GetAllMatches(ByVal findString As String, ByVal dupString As String, ByVal searchRng As Worksheet) As String
Dim foundCell As Range
Dim concatenatedString As String
concatenatedString = vbNullString
With Intersect(searchRng.Columns(1), searchRng.UsedRange)
Set foundCell = .Find(findString)
If foundCell Is Nothing Then Exit Function
If Not foundCell Is Nothing Then concatenatedString = foundCell.Offset(, 1)
Dim currMatch As Long
currMatch = 0
For currMatch = 1 To WorksheetFunction.CountIf(.Cells, findString)
Set foundCell = .Find(What:=findString, After:=foundCell, _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not foundCell Is Nothing And InStr(1, dupString, concatenatedString) = 0 Then
concatenatedString = concatenatedString & "/" & foundCell.Offset(, 1)
Else
concatenatedString = foundCell.Offset(, 1)
End If
Next currMatch
End With
GetAllMatches = concatenatedString
End Function
Output in Feuil2
Maybe something like this instead?
Sub Test()
Dim i As Long, myrow As Long, lastrow As Long
Dim sht1 As Worksheet, sht2 As Worksheet
Set sht1 = ThisWorkbook.Worksheets("Sheet1")
Set sht2 = ThisWorkbook.Worksheets("Sheet2")
lastrow = 1
For i = 1 To 7
If Application.WorksheetFunction.CountIf(sht1.Range("A:A"), sht2.Range("F" & i).Value) = 0 Then
If i = 1 Then
lastrow = 1
Else
lastrow = sht1.Cells(sht1.Rows.Count, "A").End(xlUp).Row + 1
End If
sht1.Range("A" & lastrow).Value = sht2.Range("F" & i).Value
sht1.Range("B" & lastrow).Value = sht2.Range("G" & i).Value
Else
sht1.Range("B" & sht1.Columns("A:A").Find(What:=sht2.Range("F" & i).Value).Row).Value = sht1.Range("B" & sht1.Columns("A:A").Find(What:=sht2.Range("F" & i).Value).Row).Value & "/" & sht2.Range("G" & i).Value
End If
Next i
End Sub
How do I compare a mapping table (values in different cells) in excel and map the value of that header to my main database.
Main Database:
Mapping Table:
Tanu's Sheet:
It should map the headers(wgt, ht, bmi, etc) of the file (tanu, sweety, Raju) and compare it with main database and replace it with the headers of main database
The code written so far
Sub SelectColumn()
Dim xColIndex As Integer
Dim xRowIndex As Integer
xIndex = Application.ActiveCell.Column
xRowIndex = Application.ActiveSheet.Cells(Rows.Count,
xIndex).End(xlUp).Row
Range(Cells(2, xIndex), Cells(xRowIndex, xIndex)).Select
End Sub
Can't get through
This code will check your mapping table and replace headers in each of their Sheets for each workbook tanu, sweety and etc, (it will look for the headers in the range A1:Z1000, change this if you need it to be a bigger range):
Sub foo3()
Dim Wbook As Workbook
Dim wSheet As Worksheet
Dim wb As ThisWorkbook
Set wb = ThisWorkbook
Application.DisplayAlerts = False
LastCol = wb.Sheets("LMal").Cells(1, Columns.Count).End(xlToLeft).Column 'Check how many columns in the Mapping Table
LastRow = wb.Sheets("LMal").Cells(Rows.Count, "A").End(xlUp).Row 'Check how many rows in the Mapping Table
For i = 2 To LastCol
Filename = "C:\Users\tanu\Desktop\" & wb.Sheets("LMal").Cells(1, i) & ".xlsx" ' Get the Sheet name such as tanu, sweety, etc
Set Wbook = Workbooks.Open(Filename)
For x = 2 To LastRow ' loop through rows
Search = wb.Sheets("LMal").Cells(x, i).Value
On Error Resume Next
For Each wSheet In Wbook.Worksheets
Set strGotIt = wSheet.Cells.Find(What:=Search, After:=wSheet.Cells(1, 1), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=True)
If strGotIt <> vbNullString Then
wSheet.Cells(strGotIt.Row, strGotIt.Column).Value = wb.Sheets("LMal").Cells(x, 1).Value 'replace the value in tanu's sheet
On Error GoTo 0
End If
Next
On Error GoTo 0
Next x
Wbook.Close SaveChanges:=True
Application.DisplayAlerts = True
Next i
End Sub
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")