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
Related
wish you all the best.
I am making a code using VBA to find and detect errors from one sheet and paste the values from column A and B from the row of the error to the destination sheet.
my code is mostly working my issue is the content that is pasting which is the error cell and the next one to the right instead of the values from A and B (example: imagine macro is running all values in column K and there is an error in K85, it is pasting K85 and L85, instead of A85 and B85)
Sub Copy_NA_Values()
Dim rng As Range
Dim firstBlank As Range
Dim shtSource As Worksheet
Dim shtDestination As Worksheet
Set shtSource = ThisWorkbook.Sheets("JE Royalty detail") 'Change to the name of the source sheet
Set shtDestination = ThisWorkbook.Sheets("DB") 'Change to the name of the destination sheet
Set rng = shtSource.Range("F:F").SpecialCells(xlCellTypeFormulas, xlErrors)
For Each cell In rng
If IsError(Range("F:F")) = False Then
Set firstBlank = shtDestination.Range("K" & Rows.Count).End(xlUp).Offset(1, 0)
cell.Resize(1, 2).Copy firstBlank
End If
Next cell
End Sub
How can I make it so it will paste the correct cells i have tried to use paste special but I might've used it wrongly but I had errors, all help apreciated.
Have a good one.
it is pasting K85 and L85, instead of A85 and B85
Try replacing:
cell.Resize(1, 2).Copy firstBlank
with
shtSource.Range("A" & cell.Row & ":B" & cell.Row).Copy firstBlank
To paste only values, do this instead:
shtSource.Range("A" & cell.Row & ":B" & cell.Row).Copy
firstBlank.PasteSpecial (xlPasteValues)
Copy Values When Matching Error Values
Option Explicit
Sub BackupErrorValues()
Const SRC_NAME As String = "JE Royalty detail"
Const SRC_ERROR_RANGE As String = "F:F"
Const SRC_COPY_RANGE As String = "A:B"
Const DST_NAME As String = "DB"
Const DST_FIRST_CELL As String = "A2"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Sheets(SRC_NAME)
Dim srg As Range
On Error Resume Next ' to prevent error if no error values
Set srg = Intersect(sws.UsedRange, sws.Columns(SRC_ERROR_RANGE)) _
.SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If srg Is Nothing Then
MsgBox "No cells with error values found.", vbExclamation
Exit Sub
End If
Set srg = Intersect(srg.EntireRow, sws.Range(SRC_COPY_RANGE))
Dim cCount As Long: cCount = srg.Columns.Count
Dim dws As Worksheet: Set dws = wb.Sheets(DST_NAME)
If dws.FilterMode Then dws.ShowAllData ' prevent failure of 'Find' method
Dim dCell As Range
With dws.UsedRange
Set dCell = .Find("*", , xlFormulas, , xlByRows, xlPrevious)
End With
If dCell Is Nothing Then
Set dCell = dws.Range(DST_FIRST_CELL)
Else
Set dCell = dws.Cells(dCell.Row + 1, dws.Range(DST_FIRST_CELL).Column)
End If
Dim drrg As Range: Set drrg = dCell.Resize(, cCount)
Dim sarg As Range, srCount As Long
For Each sarg In srg.Areas
srCount = sarg.Rows.Count
drrg.Resize(srCount).Value = sarg.Value
Set drrg = drrg.Offset(srCount)
Next sarg
MsgBox "Error rows backed up.", vbInformation
End Sub
I want to copy and paste columns from Sheet W2W to Sheet OTD Analysis when column F value doesn’t exist in OTD Analysis.
This code copied column F:AU instead of A:AU.
Sub Transfer()
Application.ScreenUpdating = False
Dim LastRow As Long
LastRow = Sheets("W2W").Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Dim rng As Range
Dim foundVal As Range
For Each rng In Sheets("W2W").Range("F2:F" & LastRow)
Set foundVal = Sheets("OTD Analysis").Range("F:F").Find(rng, LookIn:=xlValues, lookat:=xlWhole)
If foundVal Is Nothing Then
rng.Columns("A:AU").Copy
Sheets("OTD Analysis").Activate
b = Sheets("OTD Analysis").Cells(Rows.Count,1).End(xlUp).Row
Sheets("OTD Analysis").Cells(b + 1, 1).Select
ActiveSheet.Paste
End If
Next rng
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
You want Columns("A:AU") in reference to the entire row.
rng.EntireRow.Columns("A:AU").Copy
Transfer New Entries
Let's assume that rng is cell F2. Then
rng.Columns("A:AU") refers to the range F2:AZ2,
rng.EntireRow refers to the range A2:XFD2,
rng.EntireRow.Columns("A:AU") refers to the range A2:AU2.
Option Explicit
Sub TransferNewEntries()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source - to be read (copied) from
Dim sws As Worksheet: Set sws = wb.Worksheets("W2W")
Dim slRow As Long
slRow = sws.UsedRange.Find("*", , xlFormulas, , xlByRows, xlPrevious).Row
Dim srg As Range: Set srg = sws.Range("A2", sws.Cells(slRow, "AU"))
Dim scrg As Range: Set scrg = sws.Range("F2", sws.Cells(slRow, "F"))
' or e.g. just 'Set scrg = srg.Columns(6)'
' Destination - to be written (pasted) to
Dim dws As Worksheet: Set dws = wb.Worksheets("OTD Analysis")
Dim dlRow As Long
dlRow = dws.UsedRange.Find("*", , xlFormulas, , xlByRows, xlPrevious).Row
Dim dcrg As Range: Set dcrg = dws.Range("F2", dws.Cells(dlRow, "F"))
Dim surg As Range
Dim sCell As Range
Dim sr As Long
Dim drIndex As Variant
Dim drCount As Long
For Each sCell In scrg.Cells
sr = sr + 1 ' the n-th cell of the source column range...
' ... more importantly, the n-th row of the source range
drIndex = Application.Match(sCell.Value, dcrg, 0)
If IsError(drIndex) Then ' source value was not found
drCount = drCount + 1 ' count the rows to be copied
If surg Is Nothing Then ' combine the rows into a range...
Set surg = srg.Rows(sr)
Else
Set surg = Union(surg, srg.Rows(sr))
End If
'Else ' source value was found; do nothing
End If
Next sCell
If surg Is Nothing Then
MsgBox "No new entries (no action taken).", vbExclamation
Exit Sub
End If
Dim dfCell As Range: Set dfCell = dws.Cells(dlRow + 1, "A")
surg.Copy dfCell ' ... to be copied in one go
MsgBox "New entries copied: " & drCount, vbInformation
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 a master sheet being updated by other workbooks. "Column A" in the Master has an ID number, the other spreadsheets will also have a column let's say "B" containing that ID number.
I want to match the ID number from the other workbook to the master and where it matches in column A pull over other columns into the master to fill in the blanks under the correct headings.
I was given this macro, but it's not matching any data.
Sub Macro1()
Dim mastersheet As Worksheet
Set mastersheet = ActiveSheet
For a = 2 To 1000
ValueToCheck = Cells(a, 1).Value
fname = "File location"
Dim Workbooktocheck As Workbook
Set Workbooktocheck = Workbooks.Open("filename")
For b = 2 To 1000
valueInNew = Workbooktocheck.Sheets("Sheet1").Cells(b, 12)
If ValueToCheck = valueInNew Then
mastersheet.Cells(a, 3).Value = Workbooktocheck.Sheets("sheet1").Cells(b, 7)
End If
Next b
Next a
End Sub
Update
This is the master:
This is the spreadsheet that updates:
Match() is usually faster than a nested loop as long as you're only expecting a single matched row.
Try this:
Sub Macro1()
Dim wsMaster As Worksheet, wbToCheck As Workbook, wsCheck As Worksheet
Dim ValueToCheck, a As Long, m
Set wsMaster = ActiveSheet
Set wbToCheck = Workbooks.Open("filepathgoeshere")
Set wsCheck = wbToCheck.Worksheets("Sheet1") '<<< was missing this
For a = 2 To wsMaster.Cells(Rows.Count, 1).End(xlUp).Row
ValueToCheck = wsMaster.Cells(a, 1).Value
If Len(ValueToCheck) > 0 Then
'match is faster than using a nested loop
m = Application.Match(ValueToCheck, wsCheck.Range("L:L"), 0)
If Not IsError(m) Then
'got a match
With wsMaster.Rows(a)
.Columns("C").Value = wsCheck.Cells(m, "G").Value
'etc for other cells...
End With
End If
End If
Next a
End Sub
Update Master Worksheet
Carefully adjust the values in the constants section.
s - Source (read from), d - Destination (written to)
Option Explicit
Sub UpdateMaster()
Const sPath As String = "C:\Test\Source.xlsx"
Const sName As String = "Sheet1"
Const sCol As String = "L"
Const sColsList As String = "A,B,C"
Const sfRow As Long = 1 ' header row
Const dName As String = "Master"
Const dCol As String = "A"
Const dfRow As Long = 1 ' header row
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
Dim sws As Worksheet: Set sws = swb.Worksheets(sName)
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
' Headers
Dim sCols() As String: sCols = Split(sColsList, ",")
Dim cUpper As Long: cUpper = UBound(sCols)
Dim dCols() As Long: ReDim dCols(0 To cUpper)
Dim cIndex As Variant
Dim n As Long
For n = 0 To cUpper
cIndex = Application.Match( _
sws.Rows(sfRow).Columns(sCols(n)), dws.Rows(dfRow), 0)
If IsNumeric(cIndex) Then
dCols(n) = cIndex
Else
MsgBox "A header was not found", vbCritical, "Update Master"
Exit Sub
End If
Next n
' Column Ranges
Dim sfCell As Range: Set sfCell = sws.Cells(sfRow + 1, sCol)
Dim slCell As Range: Set slCell = sws.Cells(sws.Rows.Count, sCol).End(xlUp)
Dim srg As Range: Set srg = sws.Range(sfCell, slCell)
Dim dfCell As Range: Set dfCell = dws.Cells(dfRow + 1, dCol)
Dim dlCell As Range: Set dlCell = dws.Cells(dws.Rows.Count, dCol).End(xlUp)
Dim drg As Range: Set drg = dws.Range(dfCell, dlCell)
' Write
Application.ScreenUpdating = False
Dim dCell As Range
Dim rIndex As Variant
For Each dCell In drg.Cells
rIndex = Application.Match(dCell.Value, srg, 0)
If IsNumeric(rIndex) Then
For n = 0 To cUpper
dCell.EntireRow.Columns(dCols(n)).Value _
= srg.Cells(rIndex).EntireRow.Columns(sCols(n)).Value
Next n
End If
Next dCell
Application.ScreenUpdating = True
' Inform
MsgBox "Data updated.", vbInformation, "Update Master"
End Sub
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