I have below code which is working fine with one sheet data i.e on sheet 2, now i wanted to run same code on other worksheet too i.e sheet 4, sheet 5, sheet 6 and sheet 7 to cut the data from these sheet and paste it in sheet 3 as per below codes.
the below code will work as below
I have master Data in Sheet 2 (Column B) and search criteria in Sheet 1 (Column A), i want VBA to find all the data from Sheet 1 (Column A) in Sheet 2 (Column B) if found cut the entire row and past it into Sheet 3 next available row.
i wanted to run same code on other worksheet too i.e sheet 4, sheet 5, sheet 6 and sheet 7 to cut the data from these sheet and paste it in sheet 3 as per below codes.
Option Explicit
Sub remDup()
' Constants
Const sName As String = "Sheet1"
Const sFirst As String = "A1"
Const lName As String = "Sheet2"
Const lFirst As String = "B1"
Const dName As String = "Sheet3"
Const dFirst As String = "A1"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(lName)
Dim srg As Range: Set srg = refColumn(sws.Range(lFirst))
If srg Is Nothing Then Exit Sub
Dim sData As Variant: sData = getColumn(srg)
' Lookup
Dim lws As Worksheet: Set lws = wb.Worksheets(sName)
Dim lrg As Range: Set lrg = refColumn(lws.Range(sFirst))
If lrg Is Nothing Then Exit Sub
Dim lData As Variant: lData = getColumn(lrg)
' Match
Dim trg As Range
Dim i As Long
For i = 1 To UBound(sData)
If foundMatchInVector(sData(i, 1), lData) Then
Set trg = getCombinedRange(trg, srg.Cells(i))
End If
Next i
' Destination
If Not trg Is Nothing Then
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' This is a kind of a ridiculous use of "refColumn".
Dim drg As Range: Set drg = refColumn(dws.Range(dFirst))
If drg Is Nothing Then
Set drg = dws.Range(dFirst).EntireRow
Else
Set drg = drg.Cells(drg.Cells.Count).Offset(1).EntireRow
End If
trg.EntireRow.Copy drg
trg.EntireRow.Delete
End If
End Sub
' Assumptions: 'FirstCellRange' is a one-cell range e.g. 'Range("A1")'.
' Returns: Either the range from 'FirstCellRange' to the bottom-most
' non-empty cell in the column, or 'Nothing' if all cells
' below 'FirstCellRange' (incl.) are empty.
Function refColumn( _
ByVal FirstCellRange As Range) _
As Range
With FirstCellRange
Dim cel As Range
Set cel = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If Not cel Is Nothing Then
Set refColumn = .Resize(cel.Row - .Row + 1)
End If
End With
End Function
' Assumptions: 'rg' is a one-column range e.g. 'Range("A1")', 'Range("A1:A2")'.
' Returns: A 2D one-based one-column array.
Function getColumn( _
rg As Range) _
As Variant
If rg.Rows.Count > 1 Then
getColumn = rg.Value
Else
Dim OneElement As Variant: ReDim OneElement(1 To 1, 1 To 1)
OneElement(1, 1) = rg.Value
getColumn = OneElement
End If
End Function
' Assumptions: 'MatchValue' is a simple data type (not an object or an array).
' 'Vector' is a structure that 'Application.Match' can handle,
' e.g. a 1D array, a one-column or one-row range or 2D array.
' Returns: 'True' or 'False' (boolean).
' Remarks: Error values and blanks are ignored ('False').
Function foundMatchInVector( _
ByVal MatchValue As Variant, _
ByVal Vector As Variant) _
As Boolean
If Not IsError(MatchValue) Then
If Len(MatchValue) > 0 Then
foundMatchInVector _
= IsNumeric(Application.Match(MatchValue, Vector, 0))
End If
End If
End Function
' Assumptions: 'AddRange' is not 'Nothing' and it is in the same worksheet
' as 'BuiltRange'.
' Returns: A range (object).
Function getCombinedRange( _
ByVal BuiltRange As Range, _
ByVal AddRange As Range)
If BuiltRange Is Nothing Then
Set getCombinedRange = AddRange
Else
Set getCombinedRange = Union(BuiltRange, AddRange)
End If
End Function
Change the constant to a variable and put the main part of your code in a loop. For example (untested)
Option Explicit
Sub remDup()
' Constants
Const sName As String = "Sheet1"
Const sFirst As String = "A1"
'Const lName As String = "Sheet2"
Const lFirst As String = "B1"
Const dName As String = "Sheet3"
Const dFirst As String = "A1"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Lookup
Dim lws As Worksheet: Set lws = wb.Worksheets(sName)
Dim lrg As Range: Set lrg = refColumn(lws.Range(sFirst))
If lrg Is Nothing Then Exit Sub
Dim lData As Variant: lData = getColumn(lrg)
' Match
Dim trg As Range
Dim i As Long
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim drg As Range: Set drg = refColumn(dws.Range(dFirst))
' Source
Dim sws As Worksheet
Dim srg As Range:
Dim sData As Variant
Dim lname As Variant
For Each lname In Array("Sheet2", "Sheet4", "Sheet5", "Sheet6", "Sheet7")
' Source
Set sws = wb.Worksheets(lname)
Set srg = refColumn(sws.Range(lFirst))
If Not srg Is Nothing Then
sData = getColumn(srg)
' Match
For i = 1 To UBound(sData)
If foundMatchInVector(sData(i, 1), lData) Then
Set trg = getCombinedRange(trg, srg.Cells(i))
End If
Next i
' Destination
If Not trg Is Nothing Then
trg.EntireRow.Copy drg
trg.EntireRow.Delete
Set drg = drg.Offset(1)
End If
End If
Next
End Sub
Related
The macro is working with hard coded inputs but I need loops for debugging and future growth. I don't know the best way to set this up.
Range("b3:b8:) are the cells I would like to loop over.
If cell.value = 1 then
Set var1 = range("a3:aq3") (* This range always has the same row number as cell in loop*)
Set var2 = range("a9:aq9") (*This range always 6 greater than row of cell in loop.)
End if
Next cell
Thanks
Loop Through Rows of a Range
Option Explicit
Sub LoopThroughRows()
Const srgAddress As String = "A3:AQ8"
Const scCol As Long = 2
Const sCriteria As String = "1"
Dim sws As Worksheet: Set sws = ActiveSheet ' improve, e.g.:
'Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
'Dim sws As Worksheet: Set sws = wb.Worksheets("Sheet1")
Dim srg As Range: Set srg = sws.Range(srgAddress) ' last use of 'sws'
Dim srCount As Long: srCount = srg.Rows.Count
Dim srg1 As Range
Dim srg2 As Range
Dim sCell As Range
Dim sr As Long
For Each sCell In srg.Columns(scCol).Cells ' don't forget '.Cells'!
sr = sr + 1 ' monitoring each range row (not worksheet row)
If CStr(sCell.Value) = sCriteria Then ' also avoiding error values
Set srg1 = srg.Rows(sr)
Set srg2 = srg1.Offset(srCount)
' Continue... e.g.:
Debug.Print sr, sCell.Address(0, 0), _
srg1.Address(0, 0), srg2.Address(0, 0)
Else ' not equal to sCriteria (usually do nothing)
' e.g.:
Debug.Print sr, sCell.Address(0, 0), "Nope."
End If
Next sCell
End Sub
Have you tried using a for loop?
Eg:
For Each Cell in Range("B3:B8")
If Cell.Value = 1 Then
Set var1 = range("a3:aq3")
Else
Set var2 = range("a9:aq9")
End If
Next Cell
I am trying to extract data from different sheets in a summary sheet.
The referencing does not work.
Sub Summary_LPI()
Dim wkSht As Worksheet, wsC As Worksheet, rngSearch As Range
Dim shNCell As Range
Set wsC = Sheets("Summary")
Set rngSearch = wsC.Range("A2:A60")
For Each wkSht In ThisWorkbook.Worksheets
'find the sheet name cell in rngSearch:
Set shNCell = rngSearch.Find(what:=wkSht.Name, LookIn:=xlValues, Lookat:=xlWhole,
MatchCase:=False)
'if found:
If Not shNCell Is Nothing Then
'copy the below built array in the necessary place
wkSht.Range("AZ56").Value = wsC.Range(shNCell.Offset(0, 6), shNCell.Offset(1, 6)).Value
End If
Next wkSht
End Sub
Copy Data Into a Summary Worksheet
Adjust the values in the constants section.
The order of the columns in the Summary worksheet needs to be the same as in each individual worksheet.
The number of columns to be pulled is defined by the last non-empty column in the first (header) row of the Summary worksheet.
Option Explicit
Sub Summary_LPI()
' s - Source, d - Destination
Const sfvCol As String = "AY" ' First Value Column
Const dName As String = "Summary"
Const dlCol As String = "A" ' Lookup Column
Const dfvColString As String = "F" ' First Value Column
Const dhRow As Long = 1 ' Header Row
Dim wb As Workbook: Set wb = ThisWorkbook
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dfRow As Long: dfRow = dhRow + 1 ' First Row
Dim dlrow As Long ' Last Row
dlrow = dws.Cells(dws.Rows.Count, dlCol).End(xlUp).Row
If dlrow < dfRow Then Exit Sub ' no data
Dim dlcrg As Range ' Lookup Column Range
Set dlcrg = dws.Range(dws.Cells(dfRow, dlCol), dws.Cells(dlrow, dlCol))
Dim dfvCol As Long: dfvCol = dws.Columns(dfvColString).Column
Dim dlvCol As Long ' Last Value Column
dlvCol = dws.Cells(dhRow, dws.Columns.Count).End(xlToLeft).Column
If dlvCol < dfvCol Then Exit Sub ' no data
Dim vcCount As Long: vcCount = dlvCol - dfvCol + 1 ' Value Columns Count
Application.ScreenUpdating = False
Dim sws As Worksheet
Dim svrrg As Range ' Value Row Range
Dim svRow As Long ' Value Row
Dim dvrrg As Range ' Value Row Range
Dim dlCell As Range ' Lookup Cell
For Each dlCell In dlcrg.Cells
Set dvrrg = dlCell.EntireRow.Columns(dfvCol).Resize(, vcCount)
On Error Resume Next
Set sws = wb.Worksheets(CStr(dlCell.Value))
On Error GoTo 0
If sws Is Nothing Then ' worksheet doesn't exist
dvrrg.ClearContents ' remove if you want to keep the previous
Else ' worksheet exists
svRow = sws.Cells(sws.Rows.Count, sfvCol).End(xlUp).Row
Set svrrg = sws.Cells(svRow, sfvCol).Resize(, vcCount)
dvrrg.Value = svrrg.Value
Set sws = Nothing
End If
Next dlCell
Application.ScreenUpdating = True
MsgBox "Summary updated."
End Sub
In Excel I'm looking for a VBA macro to do the following:
Search "Sheet2" range A2:Q3500 for any cells containing data (not empty), and copy only those cells.
Paste those cells' exact values into "Sheet3" starting with cell A2.
When I say "exact value" I just mean text/number in the cell is exactly the same as it appeared when copied, no different formatting applied.
Any guidance would be super appreciated, thank you!
Copy Filtered Data
The following will copy the complete table range and then delete the 'empty' rows.
Adjust the values in the constants section.
Option Explicit
Sub CopyFilterData()
' Source
Const sName As String = "Sheet2"
Const sFirst As String = "A1"
' Destination
Const dName As String = "Sheet3"
Const dFirst As String = "A1"
Const dfField As Long = 1
Const dfCriteria As String = "="
' Both
Const Cols As String = "A:Q"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
If sws.AutoFilterMode Then sws.AutoFilterMode = False
Dim sfCell As Range: Set sfCell = sws.Range(sFirst)
Dim slCell As Range
With sfCell.Resize(sws.Rows.Count - sfCell.Row + 1)
Set slCell = .Find("*", , xlFormulas, , , xlPrevious)
End With
If slCell Is Nothing Then Exit Sub ' no data in column range
Dim rCount As Long: rCount = slCell.Row - sfCell.Row + 1
If rCount = 1 Then Exit Sub ' only headers
Dim scrg As Range: Set scrg = sfCell.Resize(rCount) ' Criteria Column Range
Dim srg As Range: Set srg = scrg.EntireRow.Columns(Cols) ' Table Range
Dim cCount As Long: cCount = srg.Columns.Count
Application.ScreenUpdating = False
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
If dws.AutoFilterMode Then dws.AutoFilterMode = False
dws.UsedRange.Clear
Dim dfcell As Range: Set dfcell = dws.Range(dFirst)
Dim drg As Range: Set drg = dfcell.Resize(rCount, cCount) ' Table Range
srg.Copy drg ' copy
Dim ddrg As Range: Set ddrg = drg.Resize(rCount - 1).Offset(1) ' Data Range
drg.AutoFilter dfField, dfCriteria
Dim ddfrg As Range ' Data Filtered Range
On Error Resume Next
Set ddfrg = ddrg.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
dws.AutoFilterMode = False
If Not ddfrg Is Nothing Then
ddfrg.EntireRow.Delete ' delete 'empty' rows
End If
'drg.EntireColumn.AutoFit
'wb.Save
Application.ScreenUpdating = True
MsgBox "Data copied.", vbInformation, "Copy Filtered Data"
End Sub
The code below should help you.
Sub CopyNonEmptyData()
Dim intSheet3Row As Integer
intSheet3Row = 2
For Each c In Range("A2:Q3500")
If c.Value <> "" Then
Sheets("Sheet3").Range("A" & intSheet3Row).Value = c.Value
intSheet3Row = intSheet3Row + 1
End If
Next c
End Sub
I have a code that selects non empty cells in column C. Now If I want to select these cells in my autofilter it only pics the first found value of OutRng. How do i fix this?
Sub SelectNonBlankCells()
Sheets("Rekenblad").Select
Dim Rng As Range
Dim OutRng As Range
Dim xTitle As String
SearchCol = "10"
On Error Resume Next
xTitle = Range("C:C")
Set InputRng = Range("C:C")
For Each Rng In InputRng
If Not Rng.Value = "" Then
If OutRng Is Nothing Then
Set OutRng = Rng
Else
Set OutRng = Application.Union(OutRng, Rng)
End If
End If
Next
If Not (OutRng Is Nothing) Then
OutRng.Copy
Sheets("Plakken").Select
ActiveSheet.Range("$A$1:$K$13").AutoFilter Field:=10, Criteria1:=Array(OutRng) _
, Operator:=xlFilterValues
End If
End Sub
AutoFilter on Multiple (an Array of) Values
Range("C:C") is quite a huge range and it could take ages to get processed.
OutRng.Copy makes no sense unless you plan to copy it somewhere.
Since OutRng is declared as a range, Array(OutRng) is an array containing one element which is the actual range (object, not values).
If a range contains more than one cell and is contiguous (a single range, one area), you can use OutRng.Value but this is a 2D one-based array which in this case (it's one-column array) could be converted to a 1D one-based array using Application.Transpose(OutRng.Value) with its limitations. But since you have combined various cells into a range, it is expected that the range is non-contiguous (has several areas, is a multi-range), you're again at a dead end.
No matter what, it was an interesting try (IMHO).
Option Explicit
Sub FilterRange()
' Source
Const sName As String = "Rekenblad"
Const sCol As String = "C"
Const sfRow As Long = 2
' Destination
Const dName As String = "Plakken"
Const dField As Long = 10
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Create a reference to the Source Range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
'If sws.AutoFilterMode Then sws.AutoFilterMode = False
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, sCol).End(xlUp).Row
Dim srCount As Long: srCount = slRow - sfRow + 1
If srCount < 1 Then Exit Sub ' no data
Dim srg As Range: Set srg = sws.Cells(sfRow, sCol).Resize(srCount)
' Write the values from the Source Range to the Source Array ('sData').
Dim sData As Variant
If srCount = 1 Then ' one cell
ReDim sData(1 To 1, 1 To 1): sData(1, 1) = srg.Value
Else ' multiple cells (in column)
sData = srg.Value
End If
' Write the unique values from the Source Array to the keys
' of a dictionary ('dict').
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare ' A = a
Dim Key As Variant
Dim r As Long
For r = 1 To srCount
Key = sData(r, 1)
If Not IsError(Key) Then ' not error value
If Len(Key) > 0 Then ' not blank
dict(CStr(Key)) = Empty
'Else ' blank
End If
' Else ' error value
End If
Next r
If dict.Count = 0 Then Exit Sub ' only blanks and error values
' Filter the Destination Range ('drg') by the values in the dictionary.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
If dws.AutoFilterMode Then dws.AutoFilterMode = False ' remove previous
Dim drg As Range: Set drg = dws.Range("A1").CurrentRegion
' If the previous line doesn't work, use another way,
' or revert to the static:
'Set drg = dws.Range("A1:K13")
drg.AutoFilter dField, dict.Keys, xlFilterValues
'dws.activate
End Sub
am trying to make my code better, so the first thing I am trying to do is to remove all usage of selects and selection from my code.
The problem am facing is I am unable to get a stable code without using Selection.
PFB code am using to make the selection
Sub findandCopyVisbleCellsinColumn(ByRef wb As Workbook, ByRef ws As Worksheet, ByRef columnNumber As Long)
Dim lrow, lcolumn As Long
With wb
With ws
ws.Activate
Selection.End(xlToLeft).Select
ws.Range(Cells(1, columnNumber).Address).Offset(1, 0).Select
ws.Range(Selection, Selection.End(xlDown)).Select
Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
End With
End With
End Sub
PFB Code am using for calling above code and pasting the values
emptyCell = range_End_Method(wb, ws, 3)
Call findandCopyVisbleCellsinColumn(wb, ws1, 7)
ws.Range("C" & emptyCell).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
What I have done until now
With ws
ws.Activate
Selection.End(xlToLeft).Select
lrow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
lcolumn = ws.Cells(1, ws1.Columns.Count).End(xlToLeft).Column
.Range(.Cells(.Cells(2, columnNumber).Address).Offset(1, 0), lrow, lcolumn).Copy
End With
this is giving an error for invalid property assignment. I suspect its due to assigning cells to cells, Please point me in the right direction.
Thanks in advance.
Copy Visible Cells in a Column
The feedback to my post Function vs Sub(ByRef) was kind of groundbreaking to my understanding of the difference between ByVal and ByRef (and accidentally error handling, too). Basically, to your surprise, you will rarely need ByRef.
Option Explicit
Sub YourPBFCode()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets("source")
Dim dws As Worksheet: Set dws = wb.Worksheets("target")
CopyVisibleCellsInColumn sws.Range("G2"), dws.Range("C2")
End Sub
' Just a test (example).
Sub CopyVisibleCellsInColumnTEST()
Const sName As String = "Sheet1"
Const sAddr As String = "A2"
Const dName As String = "Sheet2"
Const dAddr As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sfCell As Range: Set sfCell = sws.Range(sAddr)
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim difCell As Range: Set difCell = dws.Range(dAddr)
CopyVisibleCellsInColumn sfCell, difCell
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Copies the visible cells of a one-column range to another
' one-column range. The source range is defined by its first cell
' and the last cell in its column of its worksheet's used range.
' The column of the destination range is defined by its first
' initial cell. The first row of the destination range
' will be the row of the last non-empty cell in the column
' increased by one aka the first available row.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub CopyVisibleCellsInColumn( _
ByVal SourceFirstCell As Range, _
ByVal DestinationInitialFirstCell As Range)
If SourceFirstCell Is Nothing Then Exit Sub
If DestinationInitialFirstCell Is Nothing Then Exit Sub
' Create a reference to the Source Range ('srg').
Dim sfCell As Range: Set sfCell = SourceFirstCell.Cells(1)
Dim srg As Range: Set srg = RefVisibleCellsinColumn(sfCell)
If srg Is Nothing Then Exit Sub ' no data
' Create a reference to the Destination Range ('drg').
Dim difCell As Range: Set difCell = DestinationInitialFirstCell.Cells(1)
Dim dfCell As Range: Set dfCell = RefFirstAvailableCellInColumn(difCell)
If dfCell Is Nothing Then Exit Sub ' no available cells
Dim srCount As Long: srCount = srg.Cells.Count
If srCount > dfCell.Worksheet.Rows.Count - dfCell.Row + 1 Then
Exit Sub ' does not fit
End If
Dim drg As Range: Set drg = dfCell.Resize(srCount)
' Write values from the Source Range to the Destination Array ('dData').
Dim dData As Variant: dData = GetColumnMultiRange(srg)
' Write values from the Destination Array to the Destination Range.
drg.Value = dData
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to the visible cells of the range
' at the intersection of the one-column range from the first cell
' of a range ('FirstCellRange') to the bottom-most worksheet cell,
' and the used range of the worksheet.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefVisibleCellsinColumn( _
ByVal FirstCellRange As Range) _
As Range
If FirstCellRange Is Nothing Then Exit Function
Dim fCell As Range: Set fCell = FirstCellRange.Cells(1)
Dim wsrCount As Long: wsrCount = fCell.Worksheet.Rows.Count
Dim crg As Range: Set crg = fCell.Resize(wsrCount - fCell.Row + 1)
On Error Resume Next
Set RefVisibleCellsinColumn = _
Intersect(crg.Worksheet.UsedRange, crg).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: In the one-column range ('crg') from the first cell ('fCell')
' of a range ('FirstCellRange') to the bottom-most worksheet cell,
' creates a reference to the first available cell
' i.e. the cell below the last non-empty cell ('lCell.Offset(1)').
' If the one-column range ('crg') is empty,
' the first cell ('fCell') is also the first available cell.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefFirstAvailableCellInColumn( _
ByVal FirstCellRange As Range) _
As Range
If FirstCellRange Is Nothing Then Exit Function
Dim fCell As Range: Set fCell = FirstCellRange.Cells(1)
Dim wsrCount As Long: wsrCount = fCell.Worksheet.Rows.Count
Dim crg As Range: Set crg = fCell.Resize(wsrCount - fCell.Row + 1)
Dim lCell As Range: Set lCell = crg.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then
Set RefFirstAvailableCellInColumn = fCell
Else
If lCell.Row < wsrCount Then
Set RefFirstAvailableCellInColumn = lCell.Offset(1)
End If
End If
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the values of the first columns of each single range
' of a multi-range in a 2D one-based one-column array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetColumnMultiRange( _
ByVal ColumnMultiRange As Range) _
As Variant
On Error GoTo ClearError ' too many areas, "RTE '7': Out of memory"
If ColumnMultiRange Is Nothing Then Exit Function
Dim aCount As Long: aCount = ColumnMultiRange.Areas.Count
Dim aData As Variant: ReDim aData(1 To aCount, 1 To 2)
Dim ocData As Variant: ReDim ocData(1 To 1, 1 To 1)
Dim arg As Range
Dim a As Long
Dim arCount As Long
Dim drCount As Long
For Each arg In ColumnMultiRange.Areas
a = a + 1
With arg.Columns(1)
arCount = .Rows.Count
If arCount = 1 Then ' one cell
ocData(1, 1) = .Value
aData(a, 1) = ocData
Else ' multiple cells
aData(a, 1) = .Value
End If
End With
aData(a, 2) = arCount
drCount = drCount + arCount
Next arg
'Debug.Print aCount, arCount, drCount
Dim dData As Variant: ReDim dData(1 To drCount, 1 To 1)
Dim ar As Long
Dim dr As Long
For a = 1 To aCount
For ar = 1 To aData(a, 2)
dr = dr + 1
dData(dr, 1) = aData(a, 1)(ar, 1)
Next ar
Next a
GetColumnMultiRange = dData
ProcExit:
Exit Function
ClearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Resume ProcExit
End Function
Hard to explain where you've gone wrong with your range selection.
.Range(.Cells(.Cells(2, columnNumber).Address).Offset(1, 0), lrow, lcolumn)
Range is one or more cells in the worksheet.
Cells is a single cell in the worksheet - referenced using the row number and row column or letter. So Cells(1,1) will work, as will Cells(1,"A"). Your code has supplied a complete cell address - so is trying to do Cells("A1").
This is how I'd do it without selecting anything:
Sub Test()
'Copy data from sheet1 to sheet2 in a different workbook.
CopyAndPaste ThisWorkbook.Worksheets("Sheet1"), _
Workbooks("Book4").Worksheets("Sheet2")
'Copy data from sheet1 to sheet2 in workbook that contains this code.
CopyAndPaste ThisWorkbook.Worksheets("Sheet1"), _
ThisWorkbook.Worksheets("Sheet2")
End Sub
Private Sub CopyAndPaste(Source As Worksheet, Target As Worksheet)
Dim LastCell As Range
Set LastCell = GetLastCell(Source)
With Source
'Copies a range from A1 to LastCell and pastes in Target cell A1.
.Range(.Cells(1, 1), LastCell).Copy Destination:=Target.Cells(1, 1)
End With
End Sub
Private Function GetLastCell(ws As Worksheet) As Range
Dim lLastCol As Long, lLastRow As Long
On Error Resume Next
With ws
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
If lLastCol = 0 Then lLastCol = 1
If lLastRow = 0 Then lLastRow = 1
Set GetLastCell = .Cells(lLastRow, lLastCol)
End With
On Error GoTo 0
End Function
Note the actual copy/paste is a single line:
.Range(.Cells(1, 1), LastCell).Copy Destination:=Target.Cells(1, 1)
This copies the range on the Source worksheet from cells A1 (1,1) to whatever range is returned by the GetLastCell function. As that function returns a range object it can be used directly - no need to find the address and pass that separately to another range object.
The copied cells are then pasted to cell A1 on the Target worksheet. As long as you've got the correct sheet reference the code will know which workbook the worksheet belongs to - no need for With wb:With ws - the ws reference already contains the wb reference.