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
Related
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
I have two sheets in my excel file:
Input Sheet: Sheet1
Target Sheet: Sheet2
What I want to achieve is to paste the value start from the column that I defined in cell C5 and also start from the row that I defined in cell C6. If the range defined by cell C5 and C6 already have data, then it will find the next empty row based on the column in cell C5 and paste the data in that empty row.
For example in the screenshot above, the starting column & row defined in cell C5 & C6 is B8, so the copied value will be pasted starting from cell B8 until E8. However, if the row already have data, then it will find the next empty row based on column B (which is B9) and paste it there.
I'm not sure how to modified my current script:
Public Sub CopyData()
Dim InputSheet As Worksheet ' set data input sheet
Set InputSheet = ThisWorkbook.Worksheets("Sheet1")
Dim InputRange As Range ' define input range
Set InputRange = InputSheet.Range("G6:J106")
Dim TargetSheet As Worksheet
Set TargetSheet = ThisWorkbook.Worksheets("Sheet2")
Const TargetStartCol As Long = 2 ' start pasting in this column in target sheet
Const PrimaryKeyCol As Long = 1 ' this is the unique primary key in the input range (means first column of B6:G6 is primary key)
Dim InsertRow As Long
InsertRow = TargetSheet.Cells(TargetSheet.Rows.Count, TargetStartCol + PrimaryKeyCol - 1).End(xlUp).Row + 1
' copy values to target row
TargetSheet.Cells(InsertRow, TargetStartCol).Resize(ColumnSize:=InputRange.Columns.Count).Value = InputRange.Value
End Sub
Any help or advice will be greatly appreciated!
Testing Scenario 1
Output of Testing Scenario 1
Please, try the next code:
Public Sub CopyData_()
Dim InputSheet As Worksheet: Set InputSheet = ThisWorkbook.Worksheets("Sheet1")
Dim InputRange As Range: Set InputRange = InputSheet.Range("G6:J106")
Dim arr: arr = InputRange.Value
Dim TargetSheet As Worksheet: Set TargetSheet = ThisWorkbook.Worksheets("Sheet2")
Dim TargetStartCol As String, PrimaryKeyRow As Long
TargetStartCol = TargetSheet.Range("C5").Value ' start pasting in this column in target sheet
PrimaryKeyRow = TargetSheet.Range("C6").Value ' this is the row after the result to be copied
Dim InsertRow As Long
InsertRow = TargetSheet.cells(TargetSheet.rows.Count, TargetStartCol).End(xlUp).row + 1
If InsertRow < PrimaryKeyRow Then InsertRow = PrimaryKeyRow + 1 'in case of no entry after PrimaryKeyRow (neither the label you show: "Row")
' copy values to target row
TargetSheet.cells(InsertRow, TargetStartCol).Resize(UBound(arr), UBound(arr, 2)).Value = arr
End Sub
Not tested, but if should work, I think. If something not clear or going wrong, please do not hesitate to mention the error, what it does/doesn't against you need or anything else, necessary to correct it.
Copy Data to Another Worksheet
Option Explicit
Sub CopyData()
Const sName As String = "Sheet1"
Const rgAddress As String = "G6:J106"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Worksheets(sName)
Dim rg As Range: Set rg = ws.Range(rgAddress)
WriteCopyData rg
' or just:
'WriteCopyData ThisWorkbook.Worksheets("Sheet1").Range("G6:J106")
End Sub
Sub WriteCopyData(ByVal SourceRange As Range)
Const dName As String = "Sheet2"
Const dRowAddress As String = "C6"
Const dColumnAddress As String = "C5"
Dim rCount As Long: rCount = SourceRange.Rows.Count
Dim cCount As Long: cCount = SourceRange.Columns.Count
Dim dws As Worksheet
Set dws = SourceRange.Worksheet.Parent.Worksheets(dName)
Dim dRow As Long: dRow = dws.Range(dRowAddress).Value
Dim dCol As String: dCol = dws.Range(dColumnAddress).Value
Dim dfrrg As Range: Set dfrrg = dws.Cells(dRow, dCol).Resize(1, cCount)
Dim dlCell As Range
Set dlCell = dfrrg.Resize(dws.Rows.Count - dRow + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If Not dlCell Is Nothing Then
Set dfrrg = dfrrg.Offset(dlCell.Row - dRow + 1)
End If
Dim drg As Range: Set drg = dfrrg.Resize(rCount)
drg.Value = SourceRange.Value
End Sub
I've been struggling for a while with this:
I'm trying to write a script that copies over a whole row from a sheet called 'search' into a sheet called 'order' at the click of a button. Based on if there is a value entered into that row in column M.
I have written the if statement so that it pulls the rows over that have a value bigger than 0.
However - it always pulls in ONLY the top lines of the 'search' source database - never the ones that have a value in.
The data in the source are all formulas - could this be an issue? Otherwise is there a way to copy and paste data as values?
For instance - in the below picture I want to pull over ID 1359399 and 1359403. But it will always pull over the top two lines (1359394 and 1359395).
Thanks for any help.
Sub CopySomeCells()
Dim SourceSheet As Worksheet
Dim DestinationSheet As Worksheet
Dim SourceRow As Long
Dim DestinationRow As Long
Set SourceSheet = ActiveWorkbook.Sheets("Search")
Set DestinationSheet = ActiveWorkbook.Sheets("Order")
DestinationRow = DestinationSheet.Cells(DestinationSheet.Rows.Count, 2).End(xlUp).Row + 1
For SourceRow = 2 To SourceSheet.UsedRange.Rows.Count
If SourceSheet.Range("M" & SourceRow).Value > 0 Then
SourceSheet.Range(SourceSheet.Cells(SourceRow, 1), SourceSheet.Cells(SourceRow, 29)).Copy _
DestinationSheet.Cells(DestinationRow, 2)
DestinationRow = DestinationRow + 1
End If
Next SourceRow
Range("M2:M7000").Clear
End Sub
Copy Criteria Rows Using AutoFilter
Copies rows of data that meet a criterion in a column, to another worksheet.
Option Explicit
Sub CopySomeRows()
' Source
Const sName As String = "Search"
Const sCol As Long = 13 ' M
Const sCriteria As String = ">0" ' or "<>" for not blank, ' or "=" for blank
' Destination
Const dName As String = "Order"
Const dfCol As Long = 2 ' B
' Both
Const cCount As Long = 29
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
If sws.AutoFilterMode Then sws.AutoFilterMode = False
Dim strg As Range ' Source Table Range (headers)
Set strg = sws.Range("A1").CurrentRegion.Resize(, cCount)
If strg.Rows.Count = 1 Then Exit Sub ' no data or just headers
Dim sdrg As Range ' Source Data Range (no headers)
Set sdrg = strg.Resize(strg.Rows.Count - 1).Offset(1)
strg.AutoFilter sCol, sCriteria
Dim sdvrg As Range ' Source Data Visible Range
On Error Resume Next
Set sdvrg = sdrg.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
sws.AutoFilterMode = False
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dfCell As Range
Set dfCell = dws.Cells(dws.Rows.Count, dfCol).End(xlUp).Offset(1)
If Not sdvrg Is Nothing Then
sdvrg.Copy
dfCell.PasteSpecial xlPasteValues
dws.Activate
dfCell.Select
'Application.CutCopyMode = False ' the next line does the job
sdrg.Columns(sCol).ClearContents ' or .Clear
'sws.Activate
MsgBox "Data copied.", vbInformation
Else
MsgBox "No data found.", vbExclamation
End If
End Sub
I have 2 columns A and B. I created a Sub loop to check if the value of cells in column 2 is <> "NULL" then if its not NULL I have to copy the valueof it and paste it to its counterpart row in Column A.
I tried this code but can't continue because I'm having a hard time pasting the value of the cell in column 2 to its left side column 1 counterpart it only paste in cell A2. How to paste it to every cell in the 1st column if the column 2 counterpart of it is not equal to NULL?
Sub IF_Loop()
Dim cell As Range
For Each cell In Range("TablePrac[Department]")
If cell.Value <> "NULL" Then
cell.Copy Range("A2")
End If
Next cell
End Sub
Copy Values in Excel Table
Before
After
The key difference between the two solutions is that the first 'deals' with the rows and columns of the worksheet, while the second uses the table (DataBodyRange) rows and columns (seems kind of more appropriate).
The 'cValue/CStr business' avoids the type mismatch error occurring if there is an error value.
Adjust the values in the constants section.
The Code
Option Explicit
Sub TableColumns()
Const wsName As String = "Sheet1"
Const dColString As String = "Table1[Column1]"
Const sColString As String = "Table1[Column2]"
Const sCriteria As String = "NULL"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim drg As Range: Set drg = ws.Range(dColString)
drg.ClearContents
Dim dCol As Long: dCol = drg.Column ' Worksheet Column
Dim srg As Range: Set srg = ws.Range(sColString)
Application.ScreenUpdating = False
Dim sCell As Range
Dim cValue As Variant
For Each sCell In srg.Cells
cValue = sCell.Value
If CStr(cValue) <> sCriteria Then
sCell.EntireRow.Columns(dCol).Value = sCell.Value ' Worksheet Row
End If
Next sCell
Application.ScreenUpdating = True
End Sub
Sub TableColumnsRowRange()
Const wsName As String = "Sheet1"
Const tblName As String = "Table1"
Const sColTitle As String = "Column2"
Const sCriteria As String = "NULL"
Const dColTitle As String = "Column1"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim tbl As ListObject: Set tbl = ws.ListObjects(tblName)
Dim sCol As Long: sCol = tbl.ListColumns(sColTitle).Index ' Table Column
Application.ScreenUpdating = False
Dim dCol As Long
With tbl.ListColumns(dColTitle)
.DataBodyRange.ClearContents
dCol = tbl.ListColumns(dColTitle).Index ' Table Column
End With
Dim srrg As Range
Dim cValue As Variant
For Each srrg In tbl.DataBodyRange.Rows ' Table (DataBodyRange) Row
cValue = srrg.Cells(sCol).Value
If CStr(cValue) <> sCriteria Then
srrg.Cells(dCol).Value = srrg.Cells(sCol).Value
End If
Next srrg
Application.ScreenUpdating = True
End Sub
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