I'm trying to copy and paste nonblank cells from sheet1 to sheet2.
I'm getting application/object error.
Public Sub CopyRows()
Sheets("Sheet1").Select
FinalRow = Cells(Rows.Count, 1).End(xlDown).Row
For x = 4 To FinalRow
ThisValue = Cells(x, 1).Value
NextRow = Cells(Rows.Count, 1).End(xlDown).Row
If Not IsEmpty(ThisValue) Then
Cells(x, 1).Resize(1, 6).Copy
Sheets(2).Select
Cells(NextRow, 1).Select
ActiveSheet.Paste
Sheets(1).Select
End If
Next x
End Sub
Copy Rows
Option Explicit
Sub CopyRows()
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets("Sheet1")
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
If slRow < 4 Then Exit Sub ' no data
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets("Sheet2")
Dim dCell As Range: Set dCell = dws.Cells(dws.Rows.Count, "A").End(xlUp)
Application.ScreenUpdating = False
Dim sCell As Range
Dim sr As Long
' Loop and copy.
For sr = 4 To slRow
Set sCell = sws.Cells(sr, "A")
If Not IsEmpty(sCell) Then
Set dCell = dCell.Offset(1)
sCell.Resize(, 6).Copy dCell
End If
Next sr
Application.ScreenUpdating = True
' Inform.
MsgBox "Rows copied.", vbInformation
End Sub
There are multiple problems in your original code. As cybernetic.nomad already pointed out, avoid using Select whenever possible. You also set your NextRow variable to always be the last row in the worksheet instead of the next available row in your destination sheet. Additionally, because of your use of .Select, you have ambiguous Cells calls.
Here is an alternate method using AutoFilter because, for this task, you can take advantage of filtering to only get populated cells without having to perform a loop:
Sub CopyRows()
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim wsSrc As Worksheet: Set wsSrc = wb.Worksheets("Sheet1")
Dim wsDst As Worksheet: Set wsDst = wb.Worksheets("Sheet2")
Dim rData As Range: Set rData = wsSrc.Range("A3", wsSrc.Cells(wsSrc.Rows.Count, "A").End(xlUp))
If rData.Rows.Count < 2 Then Exit Sub 'No data
With rData
.AutoFilter 1, "<>"
.Offset(1).Resize(, 6).Copy wsDst.Cells(wsDst.Rows.Count, "A").End(xlUp).Offset(1)
.AutoFilter
End With
End Sub
Related
I'm trying to compare the dates that I choose. I mean I'm trying to take the some items which has a date earlier. So I wrote this on VBA. But I noticed that when I run this code the output was the same as input. So it tries to find the earlier items but it couldn't compare so all items are copied.
Private Sub Macro1()
a = Worksheets("SVS").Cells(Rows.Count, 1).End(xlUp).Row
For i = 3 To a
If Worksheets("SVS").Cells(i, 22).Value < CDate("28/02/2023") Then
Worksheets("SVS").Rows(i).Copy
Worksheets("Summary").Activate
b = Worksheets("Summary").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Summary").Cells(b + 1, 1).Select
ActiveSheet.Paste
Worksheets("SVS").Activate
End If
Next i
Application.CutCopyMode = False
ThisWorkbook.Worksheets("SVS").Cells(1, 1).Select
End Sub
What is missing in the code? I wanna learn.
Check you have a valid date to compare with.
Option Explicit
Private Sub Macro1()
Dim wb As Workbook, ws As Worksheet, v
Dim lastrow As Long, i As Long, b As Long, n As Long
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Summary")
b = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
With wb.Sheets("SVS")
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 3 To lastrow
v = .Cells(i, 22) ' col V
If IsDate(v) Then
If CDbl(v) < DateSerial(2023, 2, 28) Then
b = b + 1
.Rows(i).Copy ws.Cells(b, 1)
n = n + 1
End If
End If
Next i
End With
MsgBox n & " rows copied to Summary", vbInformation, lastrow - 2 & " rows checked"
End Sub
Append If Earlier Date
Option Explicit
Sub AppendEarlierDate()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Sheets("SVS")
Dim srg As Range
Set srg = sws.Range("V3", sws.Cells(sws.Rows.Count, "V").End(xlUp))
Dim surg As Range, sCell As Range, sValue
For Each sCell In srg.Cells
sValue = sCell.Value
If IsDate(sValue) Then
If sValue < DateSerial(2023, 2, 28) Then
If surg Is Nothing Then
Set surg = sCell
Else
Set surg = Union(surg, sCell)
End If
End If
End If
Next sCell
If surg Is Nothing Then Exit Sub
Dim dws As Worksheet: Set dws = wb.Sheets("Summary")
If dws.FilterMode Then dws.ShowAllData
Dim dlCell As Range, dfCell As Range
Set dlCell = dws.Cells.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If dlCell Is Nothing Then
Set dfCell = dws.Range("A1")
Else
Set dfCell = dws.Cells(dlCell.Row + 1, "A")
End If
surg.EntireRow.Copy dfCell
End Sub
I would like to highlight matching values in two different ranges and worksheets using VBA.
Worksheet #1 is named "OVR" with the range S2:V100 (where the highlighted values should show).
Worksheet #2 is named "LS" with the range A2:A101 containing a list of names.
My goal is to highlight all the cells in the range S2:V100 (from the "OVR" worksheet) that have a match with one of the cells in the range A2:A101 (from the "LS" worksheet).
I would like to integrate it to existing VBA for this file.
Sub FindReference()
LR1 = Worksheets("LS").Cells(Rows.Count, "A").End(xlUp).Row
LR2 = Worksheets("OVR").Cells(Rows.Count, "A").End(xlUp).Row
Set rng1 = Worksheets("LS").Range("A2:A101" & LR1)
Set rng2 = Worksheets("OVR").Range("S2:V100" & LR1)
For Each rCell In rng1
rCell.Interior.ColorIndex = xlNone
rCell.Validation.Delete
result = WorksheetFunction.CountIf(rng2, rCell)
If result > 0 Then rCell.Interior.Color = vbGreen
Next
End Sub
Color Matching Cells
Option Explicit
Sub FindReference()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim lRow As Long
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets("LS")
lRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim srg As Range: Set srg = sws.Range("A2:A" & lRow)
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets("OVR")
lRow = dws.Cells(dws.Rows.Count, "A").End(xlUp).Row
Dim drg As Range: Set drg = dws.Range("S2:V" & lRow)
' Combine matching cells.
Dim durg As Range
Dim dCell As Range
Dim dValue As Variant
For Each dCell In drg.Cells
dValue = dCell.Value
If Not IsError(dValue) Then
If Len(dValue) > 0 Then
If IsNumeric(Application.Match(dValue, srg, 0)) Then
If durg Is Nothing Then
Set durg = dCell
Else
Set durg = Union(durg, dCell)
End If
End If
End If
End If
Next dCell
' Color matching cells.
drg.Interior.ColorIndex = xlNone
drg.Validation.Delete
If Not durg Is Nothing Then
durg.Interior.Color = vbGreen
End If
' Inform.
MsgBox "Data highlighted.", vbInformation
End Sub
Private Sub CommandButton1_Click()
'To count sheets in excel file
totalsheets = Worksheets.Count
For i = 1 To totalsheets
If Worksheets(i).Name <> "MasterSheet" Then
'cheking last filled row on each sheet
lastrow = Worksheets(i).Cells(Rows.Count, 1).End(xlUp).Row
For j = 1 To lastrow
Worksheets(i).Activate
Worksheets(i).Cells(j, 2).Select
Selection.Copy
Worksheets("MasterSheet").Activate
lastcln = Worksheets("MasterSheet").Cells(1, Columns.Count).End(xlToLeft)
Worksheets("MasterSheet").Cells(j, lastcln + 1).Select
ActiveSheet.Paste
Next
End If
Next
End Sub
Try this
For i = 1 To totalsheets
If Worksheets(i).Name <> "MasterSheet" Then
' change this according to your need
firstrow = 1
'last row of source
lastrow = Worksheets(i).Cells(Rows.Count, 1).End(xlUp).Row
'last column of destination
lastcln = Worksheets("MasterSheet").Cells(1, Columns.Count).End(xlToLeft)
'more efficient procedure as suggested by Nathan
Worksheets("MasterSheet").Cells(firstrow, lastcln + 1).Value = Worksheets(i).Range(Cells(firstrow, 2), Cells(lastrow, 2)).Value
End If
Next
Copy Column From Multiple Worksheets
Option Explicit
Sub CopyColumn()
' Source
Const sfRow As Long = 1
Const sCol As String = "B"
' Destination
Const dName As String = "MasterSheet"
Const dfRow As Long = 1
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim wsrCount As Long: wsrCount = wb.Worksheets(1).Rows.Count
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dfCell As Range ' Note that the left-most column cannot be column 'A'.
Set dfCell = dws.Cells(dfRow, dws.Columns.Count).End(xlToLeft).Offset(, 1)
' Declare additional variables.
Dim sws As Worksheet ' Source Worksheet
Dim srg As Range ' Source Range
Dim slCell As Range ' Source Last Cell
Dim drg As Range ' Destination Range
' Copy.
For Each sws In wb.Worksheets
If StrComp(sws.Name, dName, vbTextCompare) <> 0 Then
Set slCell = sws.Cells(wsrCount, sCol).End(xlUp)
Set srg = sws.Range(sws.Cells(sfRow, sCol), slCell)
' Either for values only (more efficient)...
Set drg = dfCell.Resize(srg.Rows.Count)
drg.Value = srg.Value
' ... or for values, formats, formulas:
'srg.Copy dfCell ' no need for 'drg'.
' (A third, most flexible option is to use 'PasteSpecial'.)
Set dfCell = dfCell.Offset(, 1) ' next column
End If
Next sws
End Sub
I'm writing some VBA to check if a value exists in a column.
lRowStatic = Worksheets("GLMapping_Static").Cells(Rows.Count, 1).End(xlUp).Row
lRow = Worksheets("GLMapping").Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lRow
If IsError(Application.Match(Worksheets("GLMapping").Cells(i, 1).Value, Worksheets("GLMapping_Static").Range(Cells(1, 1), Cells(lRowStatic, 1)), 0)) Then
MsgBox "Its not in the range"
Else
MsgBox "Its in the range"
End If
Next i
I'm confused because this code appears to work well if the "GLMapping_Static" worksheet is currently activated. If the "GLMapping" worksheet is currently activated, then I get a 1004 error.
Any idea what is causing this? I assumed there was a cell reference that didn't include a worksheet name, but I'm not seeing one.
Thanks
Qualifying Objects
The critical part is the expression
Worksheets("GLMapping_Static").Range(Cells(1, 1), Cells(lRowStatic, 1))
where Cells are not qualified so when you choose a different worksheet than GLMapping_Static, Cells will refer to the wrong worksheet resulting in a run-time error.
The first example is illustrating how to fully qualify objects (wb-ws-rg). To simplify, one could say that .Range, .Cells, .Rows, and .Columns belong to a worksheet (object), each .Worksheets belongs to a workbook (object), and each .Workbooks belongs to the Application (object).
The other examples are just showing the benefits of using variables and some possible improvements on other accounts.
The Code
Option Explicit
Sub Humongous()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim lRowStatic As Long
lRowStatic = wb.Worksheets("GLMapping_Static") _
.Cells(wb.Worksheets("GLMapping_Static").Rows.Count, 1).End(xlUp).Row
Dim lRow As Long
lRow = wb.Worksheets("GLMapping") _
.Cells(wb.Worksheets("GLMapping").Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = 1 To lRow
If IsError(Application.Match(wb.Worksheets("GLMapping").Cells(i, 1) _
.Value, wb.Worksheets("GLMapping_Static") _
.Range(wb.Worksheets("GLMapping_Static") _
.Cells(1, 1), wb.Worksheets("GLMapping_Static") _
.Cells(lRowStatic, 1)), 0)) Then
MsgBox "Its not in the range"
Else
MsgBox "Its in the range"
End If
Next i
End Sub
Sub Sheeted()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets("GLMapping_Static")
Dim sLast As Long: sLast = sws.Cells(sws.Rows.Count, 1).End(xlUp).Row
Dim srg As Range: Set srg = sws.Range(sws.Cells(1, 1), sws.Cells(sLast, 1))
Dim dws As Worksheet: Set dws = wb.Worksheets("GLMapping")
Dim dLast As Long: dLast = dws.Cells(dws.Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = 1 To dLast
If IsError(Application.Match(dws.Cells(i, 1).Value, srg, 0)) Then
MsgBox "Its not in the range"
Else
MsgBox "Its in the range"
End If
Next i
End Sub
Sub Ranged()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim srg As Range
Dim sLast As Long
With wb.Worksheets("GLMapping_Static")
sLast = .Cells(.Rows.Count, 1).End(xlUp).Row
Set srg = .Range(.Cells(1, 1), .Cells(sLast, 1))
End With
Dim drg As Range
Dim dLast As Long
With wb.Worksheets("GLMapping")
dLast = .Cells(.Rows.Count, 1).End(xlUp).Row
Set drg = .Range(.Cells(1, 1), .Cells(dLast, 1))
End With
Dim dCell As Range
For Each dCell In drg.Cells
If IsNumeric(Application.Match(dCell, srg, 0)) Then
MsgBox "Its in the range"
Else
MsgBox "Its not in the range"
End If
Next i
End Sub
You can do something like this.
Sub TryMe()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
Set ws1 = Sheets("GLMapping_Static")
Set ws2 = Sheets("GLMapping")
wb.Activate
ws1.Select
lRowStatic = ws1.Cells(Rows.Count, 1).End(xlUp).Row
lRow = ws2.Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To lRow
If IsError(Application.Match(ws2.Cells(i, 1).Value, ws1.Range(Cells(1, 1), Cells(lRowStatic, 1)), 0)) Then
MsgBox "Its not in the range"
Else
MsgBox "Its in the range"
End If
Next i
End Sub
I have developed a working macro in VBA that automatically opens a workbook and then copies the data and pastes it on a table in the workbook I am working on. I perform this task monthly.
The data set varies in rows every month but does not vary in columns.
I am running into issues when the data set in less rows than the previous month and I am forced to manually delete lines that remained in the table because the previous month had more rows.
I was hoping to add to my existing code to automatically delete the old data after pasting the new data.
I perform a manual keystroke of selecting the last row of new data and move down one cell in column A then do a Ctrl+Shift+Down+Right to grab the data and select delete. So essentially that is the task I am trying to replace.
Thanks.
Sub Import_File()
Dim wbSourceData As Workbook
Dim wbDestination As Workbook
Dim wsSourceData As Worksheet
Dim wsDestination As Worksheet
Dim strFName As String
Dim rng As Range
Dim tbl As ListObject
Dim Cl As Long
Dim Rl As Long
Set wbDestination = ThisWorkbook
Set wsDestination = wbDestination.Sheets("DataTab")
strFName = wbDestination.Worksheets("Macros").Range("C2").Value
Set wbSourceData = Workbooks.Open(strFName)
Set wsSourceData = wbSourceData.Worksheets(3)
Set tbl = wsDestination.ListObjects("Data_Report")
tbl.DataBodyRange.ClearContents
With wsSourceData
Cl = .Cells(2, .Columns.Count).End(xlToLeft).Column
Rl = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(2, "A"), .Cells(Rl, Cl))
End With
rng.Copy
wsDestination.Range("A4").PasteSpecial xlValues
Application.CutCopyMode = False
wbSourceData.Close SaveChanges:=False
End Sub
Overwrite Data Body Range
It is assumed that only values of the range will be copied.
The Code
Option Explicit
Sub overwriteDataBodyRangeTEST()
Dim rg As Range: Set rg = Range("G2:K11")
Dim tbl As ListObject: Set tbl = DataTab.ListObjects("Data_Report")
overwriteDataBodyRange rg, tbl
End Sub
Sub overwriteDataBodyRange( _
ByVal rg As Range, _
ByVal tbl As ListObject)
With tbl.DataBodyRange
Dim rCount As Long: rCount = rg.Rows.Count
Dim tCount As Long: tCount = .Rows.Count
If rg.Columns.Count = .Columns.Count Then
.Resize(rCount).Value = rg.Value
If rCount < tCount Then
.Resize(tCount - rCount).Offset(rCount).Delete
End If
Else
MsgBox "Different number of columns.", vbCritical, "Fail"
End If
End With
End Sub
EDIT
The following will copy the range to the table overwriting the previous data. If the previous data has more rows, they will be deleted.
Integrated
Option Explicit
Sub Import_File()
' Define Destination Table.
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets("DataTab")
Dim tbl As ListObject: Set tbl = dws.ListObjects("Data_Report")
' Define Source Range.
Dim sName As String: sName = dwb.Worksheets("Macros").Range("C2").Value
Dim swb As Workbook: Set swb = Workbooks.Open(sName)
Dim sws As Worksheet: Set sws = swb.Worksheets(3)
Dim rng As Range
Dim LastRow As Long
Dim LastColumn As Long
With sws
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
LastColumn = .Cells(2, .Columns.Count).End(xlToLeft).Column
Set rng = .Range(.Cells(2, "A"), .Cells(LastRow, LastColumn))
End With
' Copy Source Range to Destination Table.
With tbl.DataBodyRange
Dim tCount As Long: tCount = .Rows.Count
Dim rCount As Long: rCount = rng.Rows.Count
.Resize(rCount).Value = rng.Value ' values only
'rng.Copy .Resize(rCount) ' values, formats, and formulas
If rCount < tCount Then
.Resize(tCount - rCount).Offset(rCount).Delete
End If
End With
' Close Source Workbook (it was just read from).
swb.Close SaveChanges:=False
End Sub