Transfer data from master sheet using offset from reference cell - excel

I am trying to transfer data from one master sheet to multiple template sheets based on cell name match with sheet name of the template sheets using a specific offset in the master sheet. However the referencing does not seem to work. In my case sheet named "Combine" is the master sheet. The offset value based on match cellname is 6 columns away from the matched cell. I am getting debugging error. Can anyone fix the problem?
Sub Button5_Click()
Dim wkSht As Worksheet, wsC As Worksheet, rngSearch As Range
Dim shNCell As Range
Set wsC = Sheets("Combine")
Set rngSearch = wsC.Range("A4:A800")
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("F12").Resize(19, 1).Value = wsC.Range(shNCell.Offset(0, 6)).Value
End If
Next wkSht
End Sub

Lookup Values (VBA)
Option Explicit
Sub Button5_Click()
Const ExceptionsList As String = "Combine" ' comma-saparated, no spaces!
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the source column range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets("Combine")
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
If slRow < 4 Then Exit Sub
Dim srg As Range
Set srg = sws.Range(sws.Cells(4, "A"), sws.Cells(slRow, "A"))
' Write the names from the list (string) to an array ('Exceptions').
Dim Exceptions() As String: Exceptions = Split(ExceptionsList, ",")
Dim sCell As Range
Dim dws As Worksheet
For Each dws In wb.Worksheets
' Check if not in list.
If IsError(Application.Match(dws.Name, Exceptions, 0)) Then
' '.Cells(.Cells.Count)' ensures the search starts with
' the first cell (irrelevant in this case but good to know).
' Think: After the last cell comes the first cell.
' Using 'xlFormulas' will allow you to find even if the cell
' is in a hidden row or column. The 'formula' and the 'value'
' are the same since 'xlWhole' is used.
' 'False' is the default value of the `MatchCase` argument.
With srg
Set sCell = .Find(What:=dws.Name, After:=.Cells(.Cells.Count), _
LookIn:=xlFormulas, LookAt:=xlWhole)
End With
If Not sCell Is Nothing Then
dws.Range("F12").Value = sCell.EntireRow.Columns("G").Value
'or
'dws.Range("F12").Value = sCell.Offset(, 6).Value
'Else ' no cell found; do nothing
End If
'Else ' is in the exceptions list; do nothing
End If
Next dws
End Sub

Related

Extract values from each cell to a separate sheet

I have a file with a few sheets, I need to extract values from each not empty cell into a column on another sheet.
Would be awesome if while doing that duplicates can be removed as well.
The following code infinitely loops. I don't see how to break the loop since all the events are being used in the body of the code.
Range where the cells are being looked for on both sheets are different, that is why I used .End(xlUp) to define the last row with values in cells.
I cannot use empty cells as a trigger for stopping the loop because there are empty cells between cells with values.
Sub updt()
Dim ws As Worksheet, currWs As Worksheet, Lng As Integer, rng As Range
Set ws = wb.Worksheets("Sheet1") 'the source sheet
Set currWs = Sheets("Sheet2") 'the destination sheet
Lng = ws.Cells(Rows.Count, 1).End(xlUp).Row
Set rng = ws.Range("A2:A" & Lng)
For Each c Lng rng
If WorksheetFunction.CountIf(currWs.Range("A:A"), c.Value) = 0 Then
currWs.Range("A" & currWs.Cells(Rows.Count, 1).End(xlUp).Row)(2) = c.Value
End If
Next
End Sub
Update Column With Unique Non-Existing Values From a Column of Another Worksheet Using a Dictionary
To avoid further complications, no arrays are used.
Option Explicit
Sub UpdateWorksheet()
' Reference the workbook.
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the source worksheet, calculate the last row
' and reference the source column range.
Dim sws As Worksheet: Set sws = wb.Worksheets("Sheet1")
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim srg As Range: Set srg = sws.Range("A2:A" & slRow)
' Reference the destination worksheet and calculate the last row.
Dim dws As Worksheet: Set dws = wb.Worksheets("Sheet2")
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "A").End(xlUp).Row
' Define a dictionary (object).
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare ' case-insensitive
' Declare variables.
Dim cCell As Range
Dim cKey As Variant
' Write the unique values from the destination column range
' to the dictionary.
If dlRow > 1 Then ' 1 means 'first row - 1' i.e. '2 - 1'
Dim drg As Range: Set drg = dws.Range("A2:A" & dlRow)
For Each cCell In drg.Cells
cKey = cCell.Value
If Not IsError(cKey) Then ' exclude error values
If Len(cKey) > 0 Then ' exclude blanks
dict(cKey) = Empty
End If
End If
Next cCell
End If
' Add the unique values from the source column range
' to the dictionary.
For Each cCell In srg.Cells
cKey = cCell.Value
If Not IsError(cKey) Then ' exclude error values
If Len(cKey) > 0 Then ' exclude blanks
dict(cKey) = Empty
End If
End If
Next cCell
' Check if the dictionary is empty.
If dict.Count = 0 Then
MsgBox "No valid values found.", vbCritical
Exit Sub
End If
' Clear the previous values from the destination first cell to the bottom
' of the worksheet.
Dim dCell As Range: Set dCell = dws.Range("A2")
With dCell
.Resize(dws.Rows.Count - .Row + 1).ClearContents
End With
' Write the unique values from the dictionary to the destination worksheet.
For Each cKey In dict.Keys
dCell.Value = cKey ' write
Set dCell = dCell.Offset(1) ' reference the cell below
Next cKey
' Inform.
MsgBox "Worksheet updated.", vbInformation
End Sub
You might want to use AdvancedFilter:
Option Explicit
Sub Copy_Advanced()
Dim ws As Worksheet, currWs As Worksheet, Lng As Integer, rng As Range
Set ws = Worksheets("Sheet1") 'the source sheet
Set currWs = Sheets("Sheet2") 'the destination sheet
Lng = ws.Cells(Rows.Count, 1).End(xlUp).Row
Set rng = ws.Range("A1:A" & Lng)
ws.Range("D1").Value = ws.Range("A1").Value
ws.Range("D2") = ">0"
ws.Range(rng.Address).AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=ws.Range("D1:D2"), _
CopyToRange:=currWs.Range("A1"), _
Unique:=True
End Sub

Referencing cells from other sheets

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

How do I reference a specific, changing row in a named range based on the value of a counter variable?

I'm writing a macro that cycles through rows in a given named range, copies each individual row, and pastes them in another workbook. I can't copy the entire range for formatting reasons. The number of rows that have contents in them changes, as the macro also cycles through a list of files to pull these values from.
I created a counter variable i, that starts off as i=1. What I want to do is to have VBA first look at the named range, and select row 1 of it. Then if it contains contents, copy and paste them, and then set i+1. Back at the top, i = 2, and the macro selects row two in the named range, and runs it through the check.
I am very new to VBA and am struggling to generate the code to express this section.
Copy Named Range Rows
I would handle this by using a For Each...Next loop and by using Union to combine each critical row into a multi-range. Then I would copy the complete range in one go. Here's a basic example.
Option Explicit
Sub CopyNamedRangeRows()
' Constants
' Source
Const sName As String = "Sheet1"
Const srgName As String = "MyRange"
Const scCol As Long = 1 ' Criteria Column
' Destination
Const dName As String = "Sheet2"
Const dFirst As String = "A2"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = sws.Range(srgName)
Dim scrg As Range ' Source Copy Range
Dim srrg As Range ' Source Row Range
For Each srrg In srg.Rows
If Len(CStr(srrg.Cells(scCol).Value)) > 0 Then
If scrg Is Nothing Then
Set scrg = srrg
Else
Set scrg = Union(scrg, srrg)
End If
End If
Next srrg
If scrg Is Nothing Then
MsgBox "No rows found", vbExclamation
Exit Sub
End If
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dCell As Range: Set dCell = dws.Range(dFirst)
scrg.Copy dCell
' Finishing Touches
MsgBox "Done.", vbInformation
End Sub
If you could share the code where this needs to fit, it surely could be adapted, or even better, a function to reference the critical rows (range) could be created.
To be able to use a counter variable you could replace For Each srrg In srg.Rows with...
Dim i As Long
For i = 1 To srg.Rows.Count
Set srrg = srg.Rows(i)
... and replace Next srrg with...
Next i
Try the following code:
Sub copyRange(namedRange As Range)
Dim rng As Range
For Each rng In namedRange
'checking that the range is not empty
If rng <> "" Then
'copy it to your destination
rng.Copy anotherWB.yourdestinationWS.Range("A1")
End If
Next rng
End Sub
Sub test()
Dim myRange As Range
Set myRange = ActiveSheet.Range("A1:C5")
Call copyRange(myRange)
End Sub
If you need to copy the whole row, I can update the code.

Assistance with the (XLtoright) function. VBA

I want to paste a column selection (a2:a200) to the next available column to the right.
I am having trouble doing this.
Here I am copying the data from Tables and pasting it in the last available column to the right.
Sub CopyMonthData() Worksheets("Tables").Range("d2:d200").Copy _
Worksheets("SalesInvoicesMonth").Range("a" & Columns.Count).End(xlToLeft).Offset(1, 0) End Sub
How can I make this work?
You could use UsedRange instead.
Sub CopyMonthData()
Dim iLastCol as Integer
With Worksheets("SalesInvoicesMonth")
iLastCol = .UsedRange.Column + .UsedRange.Columns.Count - 1
Worksheets("Tables").Range("d2:d200").Copy .Cells(1,iLastCol + 1)
End With
End Sub
Declaring iLastCol helps you understand how to calculate the value but the variable is not required. You could replace it in the copy function by its actual value --> - 1 and + 1 cancel each other, so you get .Cells(1,.usedRange.Column + .UsedRange.Columns.Count) as destination range.
Copy to the Next Available Column
A Quick Fix (End)
I'm assuming that you want to copy the column range D2:D200 in the source worksheet (Tables) to the second row of the column after (next to) the last non-empty column of the destination worksheet (SalesInvoicesMonth) and that both worksheets reside in the workbook containing this code (ThisWorkbook). Also, I'm assuming that all columns in the destination worksheet have headers in the first row, which will be the row used to calculate the column number.
Sub CopyMonthDataSimple()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets("Tables")
Dim dws As Worksheet: Set dws = wb.Worksheets("SalesInvoicesMonth")
sws.Range("D2:D200").Copy _
dws.Cells(1, dws.Columns.Count).End(xlToLeft).Offset(1, 1)
End Sub
The first 1 in .Offset(1, 1) means the second row, while the second 1 means the column next to the column of the last (not hidden) header cell.
A More Flexible Solution (Find)
The following will copy the column range from the given cell (sFirst) to the bottom-most non-empty cell of the column of the source worksheet to the destination worksheet starting with the cell in the given row (dfrow) of the column after the last non-empty column.
Adjust (play with) the values in the constants section.
Sub CopyMonthData()
' Constants & Workbook
' Source
Const sName As String = "Tables"
Const sFirst As String = "D2"
' Destination
Const dName As String = "SalesInvoicesMonth"
Const dfRow As Long = 2
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Attempt to create a reference to the Source Column Range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sfCell As Range: Set sfCell = sws.Range(sFirst)
Dim sfOffset As Long: sfOffset = sfCell.Row - 1
Dim slCell As Range
' The bottom-most non-empty cell in the Source Column.
Set slCell = sfCell.Resize(sws.Rows.Count - sfOffset) _
.Find("*", , xlFormulas, , , xlPrevious)
If slCell Is Nothing Then
MsgBox "The range from the 'First Source Cell' to the bottom-most " _
& "cell of the 'Source Column' is empty.", _
vbCritical, "CopyMonthData"
Exit Sub
End If
' The following...
Dim srCount As Long: srCount = slCell.Row - sfOffset
Dim srg As Range: Set srg = sfCell.Resize(srCount)
' ... is another way of doing...
'Dim srg As Range: Set srg = sws.Range(sfCell, slCell)
' Attempt to create a reference
' to the Destination First Cell Range ('dfCell').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dlCell As Range
' The bottom-most non-empty cell in the last non-empty column.
Set dlCell = dws.Cells.Find("*", , xlFormulas, , xlByColumns, xlPrevious)
Dim dCol As Long
If dlCell Is Nothing Then ' The Destination Worksheet is empty.
dCol = 1
Else
If dlCell.Column = dws.Columns.Count Then
MsgBox "The 'Destination Last Column' is not empty.", _
vbCritical, "CopyMonthData"
Exit Sub
Else
dCol = dlCell.Column + 1
End If
End If
Dim dfCell As Range: Set dfCell = dws.Cells(dfRow, dCol)
' Copy
' Copy values, formats and formulas.
srg.Copy dfCell
' Or copy values (only) by assignment (more efficient (faster)).
'dfCell.Resize(srCount).Value = srg.Value
dfCell.EntireColumn.AutoFit
End Sub

How to copy one row of data at a time from one sheet and paste into another sheet

I want to copy one row of data at a time from one sheet and pasting into another sheet. I need to repeat this 100 times. I also need to modify a couple of column values after pasting them.
My data is not pasting into new sheet correctly.
'Get column numbers which need to be modified
PolicyReference = DataWS.Range("A1", DataWS.Range("IV1").End(xlToLeft)).Find("PolicyReference").Column
InsuredCode = DataWS.Range("A1", DataWS.Range("IV1").End(xlToLeft)).Find("InsuredCode").Column
InsuredDescription = DataWS.Range("A1", DataWS.Range("IV1").End(xlToLeft)).Find("InsuredDescription").Column
For j = 1 To 100
'Worksheets(DataWS).Range("A1:A100").Copy Worksheets(DestinationWS).Range("A1")
'1. Find last used row in the copy range based on data in column A
CopyLastRow = DataWS.Cells(DataWS.Rows.count, "A").End(xlUp).Row
'2. Find first blank row in the destination range based on data in column A
DestLastRow = DestinationWS.Cells(DestinationWS.Rows.count, "A").End(xlUp).Offset(1).Row
'3. Copy & Paste Data
DataWS.Rows(j).EntireRow.Copy DestinationWS.Range("A" & DestLastRow)
DataWS.Range("A1:A100").Copy
DestinationWS.Range("A" & Rows.count).End(xlUp).Offset(2).PasteSpecial Paste:=xlPasteValues
Next j
This code will copy all but the first row from DataWs to DestinationWs. If you want to be more selective in what you copy modifications must be made to the code in the loop, at the bottom.
Private Sub Study()
' 244
Dim DataWs As Worksheet
Dim DestinationWs As Worksheet
Dim PolicyReference As Long
Dim InsuredCode As Long
Dim InsuredDescription As Long
Dim Fnd As Range
Dim CopyLastRow As Long
Dim DestLastRow As Long
Dim R As Long ' loop counter: rows
Set DataWs = Worksheets("Sheet1")
Set DestinationWs = Worksheets("Sheet2")
With DestinationWs
DestLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'Get column numbers which need to be modified
With DataWs
Set Fnd = .Rows(1).Find("PolicyReference") ' spaces between words are permissible
' make sure the column is found before using it in your further code
If Fnd Is Nothing Then Exit Sub
PolicyReference = Fnd.Column
Set Fnd = .Rows(1).Find("InsuredCode")
If Fnd Is Nothing Then Exit Sub ' perhaps give a message before exiting
InsuredCode = Fnd.Column
Set Fnd = .Rows(1).Find("InsuredDescription")
If Fnd Is Nothing Then Exit Sub ' perhaps give a message before exiting
InsuredDescription = Fnd.Column
CopyLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False ' speeds up execution
For R = 2 To CopyLastRow ' start in row 2
DestLastRow = DestLastRow + 1
.Rows(R).Copy DestinationWs.Cells(DestLastRow, "A")
Next R
Application.ScreenUpdating = True
End With
End Sub
Columns and Ranges
I am considering these as two problems. Revealing the connection between them might lead to a more suitable solution.
The first part (including the function) illustrates how you can write the column numbers to an array which can later be used to process the data in those columns.
The second part illustrates how to copy values most efficiently. The loop is ignored.
Option Explicit
Sub ColumnsAndRanges()
Const sName As String = "Sheet1"
Const shRow As Long = 1
Const sHeadersList As String _
= "PolicyReference,InsuredCode,InsuredDescription"
Const sFirst As String = "A1"
Const dName As String = "Sheet2"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
'Part 1: Column Numbers
Dim shrg As Range: Set shrg = sws.Rows(shRow)
' Use the function 'getColumnNumbers'.
Dim sColNums As Variant: sColNums = getColumnNumbers(shrg, sHeadersList)
If IsEmpty(sColNums) Then
MsgBox "Could not find all the headers."
Exit Sub
End If
' Column Numbers Example:
Dim n As Long
For n = 1 To UBound(sColNums)
Debug.Print n, sColNums(n)
Next n
'Part 2: Copy Range Values
' Create a reference to the Source Range.
Dim slCell As Range ' Source Last Cell
Set slCell = sws.Cells(sws.Rows.Count, "A").End(xlUp)
Dim srg As Range
' Note how a cell address (sFirst) or a cell range (slCell) can be used.
Set srg = sws.Range(sFirst, slCell).EntireRow
' Create a reference to the Destination Range.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dfCell As Range ' Destination First Cell
' When 'EntireRow' is used, only "A" or 1 can be used.
Set dfCell = dws.Cells(dws.Rows.Count, "A").End(xlUp).Offset(1)
Dim drg As Range: Set drg = dfCell.Resize(srg.Rows.Count, srg.Columns.Count)
' Copy by assignment (most efficient when only values are to be copied).
drg.Value = srg.Value
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the column numbers in a one-based array.
' Remarks: The column numbers refer to the columns of the given range,
' not necessarily to the columns of the worksheet.
' If any of the headers cannot be found, 'Empty' is returned.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function getColumnNumbers( _
ByVal RowRange As Range, _
ByVal HeadersList As String, _
Optional ByVal Delimiter As String = ",") _
As Variant
If RowRange Is Nothing Then Exit Function
If Len(HeadersList) = 0 Then Exit Function
Dim Headers() As String: Headers = Split(HeadersList, Delimiter)
Dim ColNums As Variant
ColNums = Application.Match(Headers, RowRange.Rows(1), 0)
If Application.Count(ColNums) = UBound(Headers) + 1 Then
getColumnNumbers = ColNums
End If
End Function
The following one line of code using AdvancedFilter will paste data to the destination sheet.
Sub CopyDataToAnotherSheet()
DataWS.Range("A1").CurrentRegion.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=DataWS.Range("A1", _
DataWS.Cells(1, DataWS.Columns.Count).End(xlToLeft)), _
CopyToRange:=DestinationWS.Range("A1")
End Sub

Resources