I'm stuck on a code with
Runtime Error 424, Object required
The code is basically copying a column from the first sheet name "Generate" and transpose the copied column to a header row on all other active sheets except "Generate".
Could anyone help me to fix the error?
Sub Test()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
If ws.Name <> "Generate" Then
Worksheets("Generate").Range("B2:B42").Copy
ActiveWorksheet.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial Transpose:=True
End If
Next ws
End Sub
Try collecting the column header labels into an array first.
sub test()
dim hdrs as variant, w as long
with worksheets(1)
hdrs = application.transpose(.range(.cells(2, "B"), .cells(.rows.count, "B").end(xlup)).value2)
end with
for w=2 to worksheets.count
with worksheets(w)
.cells(1, "A").resize(1, ubound(hdrs)) = hdrs
'.cells(.rows.count, "A").end(xlup).offset(1, 0).resize(1, ubound(hdrs)) = hdrs
end with
next w
end sub
'alternate by worksheet name
sub test()
dim hdrs as variant, w as long
with worksheets("Generate")
hdrs = application.transpose(.range(.cells(2, "B"), .cells(.rows.count, "B").end(xlup)).value2)
end with
for w=1 to worksheets.count
if lcase(worksheets(w).name) <> "generate" then
with worksheets(w)
.cells(1, "A").resize(1, ubound(hdrs)) = hdrs
'.cells(.rows.count, "A").end(xlup).offset(1, 0).resize(1, ubound(hdrs)) = hdrs
end with
end if
next w
end sub
Related
By no means am I a VBA developer, but any help on why this isn't working would be greatly appreciated...
Problem:
Analyze all worksheets, except the last.
Check if a column I and J contain an X, if they do, get that row and copy it to the last worksheet.
Error Highlighted is at this line: For Each ws In Workbook.Worksheets. I'm not sure why.
Below is my code, but it's not compiling, and giving me the error code 424 - Object Required.
Sub CopyData()
Application.ScreenUpdating = False
Dim pasteSheet As Worksheet
Set pasteSheet = Worksheets("Remediation Summary")
For Each ws In ThisWorkbook.Worksheets
If ws.Index < (ThisWorkbook.Worksheets.Count - 1) Then
'check column i for x
For Each icell In ws.Range("i1:i200").Cells
If icell.Value Like ("X") Or ("x") Then
Rows(icell.RowIndex).Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End If
Next icell
'check column j for x
For Each jcell In ws.Range("j1:j200").Cells
If jcell.Value Like ("X") Or ("x") Then
Rows(jcell.RowIndex).Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End If
Next jcell
End If
Next ws
End Sub
Option Explicit is really a great helper - write it on the top of every module / class / worksheet. It would tell immediately, if there is some variable, which is not declared.
In your case, ws should be declared as a worksheet, as far as you are using the for-each loop to go through the Worksheets collection:
Option Explicit
Sub CopyData()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Next ws
End Sub
Option Explicit MSDN
Concerning this part - If icell.Value Like ("X") Or ("x") Then, consider rewriting it like this:
If UCase(icell) = "X" Then. It would be more understandable and Like is not needed when the comparison is without some additional signs ?*.
Excel VBA like operator
updated codebase:
Sub CopyData()
Application.ScreenUpdating = False
Dim pasteSheet As Worksheet
Set pasteSheet = Worksheets("Remediation Summary")
For Each ws In ThisWorkbook.Worksheets
If ws.Index < (ThisWorkbook.Worksheets.Count - 1) Then
'check column i for x
For Each icell In ws.Range("i0:i200").Cells
If icell.Value Like ("X") Or ("x") Then
Rows(icell.RowIndex).Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End If
Next icell
'check column j for x
For Each jcell In ws.Range("j0:j200").Cells
If jcell.Value Like ("X") Or ("x") Then
Rows(jcell.RowIndex).Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End If
Next jcell
End If
Next ws
End Sub
Based on my test, please try the code below:
Option Explicit
Sub CopyData()
Application.ScreenUpdating = False
Dim pasteSheet As Worksheet
Dim ws As Worksheet
Dim icell As Range
Dim jcell As Range
Set pasteSheet = Worksheets("Remediation Summary")
For Each ws In ThisWorkbook.Worksheets
If ws.Index < (ThisWorkbook.Worksheets.Count - 1) Then
'check column i for x
For Each icell In ws.Range("i1:i200").Cells
If UCase(icell) = "X" Or UCase(icell) = "x" Then
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow.Value = icell.EntireRow.Value
Application.CutCopyMode = False
Application.ScreenUpdating = True
End If
Next icell
'check column j for x
For Each jcell In ws.Range("j1:j200").Cells
If UCase(jcell) = "X" Or UCase(jcell) = "x" Then
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow.Value = jcell.EntireRow.Value
Application.CutCopyMode = False
Application.ScreenUpdating = True
End If
Next jcell
End If
Next ws
End Sub
Sub CopyData()
Dim pasteSheet As Worksheet, ws As Worksheet, icell As Range
Set pasteSheet = Worksheets("Remediation Summary") 'ThisWorkbook?
For Each ws In ThisWorkbook.Worksheets
If ws.Index < (ThisWorkbook.Worksheets.Count - 1) Then
'check column i,j for x
For Each icell In ws.Range("i1:i200").Cells
If LCase(icell.Value) = "x" Or LCase(icell.Offset(0, 1).Value) = "x" Then
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow.Value = _
icell.EntireRow.Value
End If
Next icell
End If
Next ws
End Sub
I'm am trying to automatically filter a column and copy/paste all the unique values to a new sheet each. Here's the code that I have been working with, however I'm facing this error when running the code:
Run-time error '1004': The extract range has a missing or invalid field name.
Sub Filter()
Application.ScreenUpdating = False
Dim x As Range
Dim rng As Range
Dim last As Long
Dim sht As String
'specify sheet name in which the data is stored
sht = "Filter This"
'change filter column in the following code
last = Sheets(sht).Cells(Rows.Count, "C").End(xlUp).Row
Set rng = Sheets(sht).Range("A1:H" & last)
Sheets(sht).Range("C1:C" & last).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=Range("AA1"), _
Unique:=True
For Each x In Range([AA2], Cells(Rows.Count, "AA").End(xlUp))
With rng
.AutoFilter
.AutoFilter Field:=3, Criteria1:=x.Value
.SpecialCells(xlCellTypeVisible).Copy
Sheets.Add(After:=Sheets(Sheets.Count)).Name = x.Value
ActiveSheet.Paste
End With
Next x
'Turn off filter
Sheets(sht).AutoFilterMode = False
With Application
.ScreenUpdating = True
.CutCopyMode = False
End With
End Sub
You can use collections to filter out the unique items, instead of using the advanced filter.
Sub UsingCollection()
Dim cUnique As Collection, ws As Worksheet, fRng As Range
Dim Rng As Range
Dim Cell As Range
Dim sh As Worksheet
Dim vNum As Variant
Set sh = ThisWorkbook.Sheets("Filter This")
Set Rng = sh.Range("C2:C" & sh.Cells(sh.Rows.Count, "C").End(xlUp).Row)
Set cUnique = New Collection
On Error Resume Next
For Each Cell In Rng.Cells
cUnique.Add Cell.Value, CStr(Cell.Value)
Next Cell
On Error GoTo 0
For Each vNum In cUnique
With sh
Set fRng = .Range("C1:H" & .Cells(.Rows.Count, "C").End(xlUp).Row)
End With
Set ws = Sheets.Add(After:=Sheets(Sheets.Count))
With ws
.Name = vNum
With fRng
.AutoFilter Field:=3, Criteria1:=vNum
fRng.Copy ws.Range("A1")
End With
.AutoFilterMode = False
End With
Next vNum
End Sub
I am using the following code:
Sub CSVParser()
Dim i As Integer
Dim x As Integer
Dim values As Range
Sheets("CSV Paste").Select
Range("A3").Select
For i = 1 To Range("A3", Range("A3").End(xlDown)).Rows.Count
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Sheets("Working Sheet 1").Select
Range("A1").Select 'problem code
Do Until ActiveCell.Value = ""
If ActiveCell.Value = "" Then
Exit Do
Else
ActiveCell.Offset(1, 0).Select
End If
Loop
ActiveSheet.Paste
Sheets("CSV Paste").Select
ActiveCell.Offset(1, 0).Select
Next
End Sub
However, the line Range("A1").Select just after Sheets("Working Sheet 1").Select is kicking up a run-time error '1004'
Does anyone know why? I have rearranged this in every way I can think of an have typed it out from scratch again.
Give this version of your code a try:
Sub CSVParser()
Dim wb As Workbook
Dim wsCSV As Worksheet
Dim wsWork As Worksheet
Set wb = ActiveWorkbook
Set wsCSV = wb.Sheets("CSV Paste")
Set wsWork = wb.Sheets("Working Sheet 1")
wsCSV.Range("A3").CurrentRegion.Copy wsWork.Cells(wsWork.Cells.Count, "A").End(xlUp).Offset(1)
End Sub
Using .Select and .Activate is not considered 'best practice'. See How to avoid using Select in Excel VBA macros. Yes, using the code from the macro recorder is a good place to start but you have to get away from the practice at some point.
Performing bulk operations is preferred to looping through an indeterminate number of rows or columns.
Option Explicit
Sub CSVParser()
Dim lastCol As Long
With Worksheets("CSV Paste")
With .Range(.Cells(3, "A"), .Cells(.Rows.Count, "A").End(xlUp))
lastCol = .CurrentRegion.Columns.Count
With .Resize(.Rows.Count, lastCol)
.Copy Destination:=Sheets("Working Sheet 1").Range("A1")
End With
End With
End With
End Sub
I think this is what you are trying to achieve (without all the unnecessary Select):
Option Explicit
Sub CSVParser()
Dim i As Long
Dim x As Long
Dim LastRow As Long
Dim PasteRow As Long
With Sheets("CSV Paste")
LastRow = .Range("A3").End(xlDown).Row
For i = 3 To LastRow
PasteRow = Sheets("Working Sheet 1").Cells(Sheets("Working Sheet 1").Rows.Count, "A").End(xlUp).Row
.Range(.Range("A" & i), .Range("A" & i).End(xlToRight)).Copy Destination:=Sheets("Working Sheet 1").Range("A" & PasteRow + 1)
Next i
End With
End Sub
So i have to copy cells A1, B2 and C3 from one workbook and add a row in anotherworkbook(in the last line) with theses values in the columns A,B,C.
Here's what i got so far, i think i'm close but i cant finish.
I havo no idea whats wrong with this syntax "Set lastrow = wNew.Cells.(Rows.Count, "A").End(xlUp).Row + 1" that seens to be the problem
Sub Botão1_Clique()
Dim wks As Worksheet
Dim wNew As Worksheet
Dim y As Workbook
Dim lastrow As Long
Application.ScreenUpdating = False
Set wks = ActiveSheet
Set y = Workbooks.Open("Y:\teste.xlsx")
Set wNew = y.Sheets("GERAL")
Set lastrow = wNew.Cells.(Rows.Count, "A").End(xlUp).Row + 1
wks.Cells(1, 1).Copy
wNew.Cells(lastrow, 1).PasteSpecial Paste:=xlPasteValues
wks.Cells(2, 2).Copy
wNew.Cells(lastrow, 2).PasteSpecial Paste:=xlPasteValues
wks.Cells(3, 3).Copy
wNew.Cells(lastrow, 3).PasteSpecial Paste:=xlPasteValues
Application.ScreenUpdating = True
End Sub
I also would like to close the Y:\teste.xlsx workbook, and display a message saying "ROW ADDED"
You do a good job properly referencing Workbooks and Worksheets but also make sure you fully qualify Cells and Rows. They are properties of the worksheet object I.e. ThisWorkbook.Worksheets("..").Rows
Sub Botão1_Clique()
Dim wks As Worksheet, wNew As Worksheet
Dim y As Workbook
Dim lastrow As Long
Application.ScreenUpdating = False
Set wks = ActiveSheet
Set y = Workbooks.Open("Y:\teste.xlsx")
Set wNew = y.Sheets("GERAL")
With wNew
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
.Cells(lastrow, 1).Value = wks.Cells(1, 1)
.Cells(lastrow, 2).Value = wks.Cells(2, 2)
.Cells(lastrow, 3).Value = wks.Cells(3, 3)
End With
'extra code as requested
y.Close True 'save changes if TRUE
MsgBox "ROW ADDED"
Application.ScreenUpdating = True
End Sub
Since hours now I'm struggling with the same problem now...
I try to copy certain rows upon a condition in column A to an other Workbook. I don't get an error message, the code runs through, but nothing happens. Somehow it seems not to "see" the lines between Then and End If. If I run the code manually, the line directly jumps to End if and further repeats the loop.
Do you have any idea what could be wrong? - Thanks for any help!
This part of my code lookes like:
Dim LastRow As Integer, i As Integer
LastRow = Workbooks("Workb1.xlsx").Sheets("Sheet1").Cells(Rows.Count,"A").End(xlUp).Row
For i = 2 To LastRow
If Cells(i, 2).Value = "848" Then
Range(Cells(i, 2), Cells(i, 14)).Select
Selection.Copy
Workbooks("destination.xlsx").Activate
Worksheets("Sheet1").Select
Range("A63976").Paste
End If
Next i
After your first comments, the edited code now is:
Dim LastRow As Integer, i As Integer
Dim ws4 As Worksheet
Set ws4 = Workbooks("Workb1").Sheets("Sheet1")
LastRow = ws4.Cells(Rows.Count, "A").End(xlUp).Row
With ws4
For i = 1 To LastRow
If .Cells(i, 1).Value = 848 Then
Range(.Cells(i, 1)).Select
Selection.Copy
Workbooks("destination.xlsx").Activate
Worksheets("Sheet1").Select
Range("A63976").Paste
End If
Next i
End With
Ok, What I actually want to do:
Always copy from source to target sheet
First only for rows, which have a 848 in column A and paste them to target. So for all those rows, which have an 848 in column A:
Copy value in the column X in “source” --> Column Y in “target”
A --> A N-->B O-->C AM -->D AH -->G P-->I E-->J F-->K
Now, only consider those cells with a 618 in column A and copy/paste, again to the firs empty cell in this column (so after the rows with 848, now the target-sheet gets completed with the 618 cells.
A --> A N-->B O-->C AM -->D T -->G P-->I E-->J F-->K
Column E and F in the target: there are formula, which have to be elongated to the end of the column
I did change that much until now, that it's not even a working code anymore...
Private Sub CommandButton1_Click()
Dim LastRow As Integer, i As Integer, erow As Integer, LastRow2 As Integer
Dim ws4 As Worksheet
Set ws4 = Workbooks("macro_source").Sheets("Sheet1")
LastRow = ws4.Cells(Rows.Count, "A").End(xlUp).Row
With ws4
For i = 2 To LastRow
If .Cells(i, 1).Value = 848 Then
Workbooks("macro_source").Sheets("Sheet1").Activate
.Cells(i, 1).Copy
Set erow = Workbooks("destination.xlsx").Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Cells(erow, 1).Select
ActiveSheet.Paste
End If
Next i
End With
End Sub
Maybe I have to add, that both files are pre-edited by the prior code, which I did not show here. And I still did not find out whether it's possible to upload the data as excel files...
Many thanks for your help again, I really stuck...
copying between books seems to go wrong fairly often even when what you have coded seems to logically be correct.
I have found in the past it's better to reference the sheet then use the reference and to use the with statement as it seems to handle range selections better
Some code below should work for you... (I have altered the paste to start at A1 and increment each time as the original code would overwrite each time it found a value - you should be able to edit to paste where you want)
Sub CopyToNewBook()
On Error Resume Next
Dim wbSrc As Workbook: Set wbSrc = Workbooks("Workb1.xlsx")
Dim wbDest As Workbook: Set wbDest = Workbooks("destination.xlsx")
If wbSrc Is Nothing Or wbDest Is Nothing Then
MsgBox "Please open both workbooks required"
Exit Sub
End If
On Error GoTo 0
Dim wsSrc As Worksheet: Set wsSrc = wbSrc.Sheets("Sheet1")
Dim wsDest As Worksheet: Set wsDest = wbDest.Sheets("Sheet1")
Dim LastRow As Long, i As Long, j As Long: j = 63976
With wsSrc
LastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
For i = 2 To LastRow
If .Cells(i, 1).Value = "848" Then
.Range(.Cells(i, 2), .Cells(i, 14)).Copy
wsDest.Range("A" & j).PasteSpecial xlPasteValues
j = j + 1
End If
Next i
End With
End Sub
UPDATE
For searching against multiple values
Sub CopyToNewBook()
On Error Resume Next
Dim wbSrc As Workbook: Set wbSrc = Workbooks("Workb1.xlsx")
Dim wbDest As Workbook: Set wbDest = Workbooks("destination.xlsx")
If wbSrc Is Nothing Or wbDest Is Nothing Then
MsgBox "Please open both workbooks required"
Exit Sub
End If
On Error GoTo 0
Dim SearchValues() As String: SearchValues = Split("848,618", ",")
Dim wsSrc As Worksheet: Set wsSrc = wbSrc.Sheets("Sheet1")
Dim wsDest As Worksheet: Set wsDest = wbDest.Sheets("Sheet1")
Dim LastRow As Long, i As Long, j As Long, z As Long: z = 63976
With wsSrc
LastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
For j = 0 To UBound(SearchValues)
For i = 2 To LastRow
If .Cells(i, 1).Value = SearchValues(j) Then
.Range(.Cells(i, 2), .Cells(i, 14)).Copy
wsDest.Range("A" & z).PasteSpecial xlPasteValues
z = z + 1
End If
Next i
Next j
End With
End Sub
To add to my comment
you're also counting the number of rows in column A and running the loop on column B. I'd also set your cells as it could be looking at the wrong sheet
Dim LastRow As Integer, i As Integer
Dim ws as worksheet
set ws = Workbooks("Workb1.xlsx").Sheets("Sheet1")
LastRow = ws.Cells(Rows.Count,"B").End(xlUp).Row
with ws
For i = 2 To LastRow
If .Cells(i, 2).Value = 848 Then
Range(.Cells(i, 2), .Cells(i, 14)).Select
Selection.Copy
Workbooks("destination.xlsx").Activate
Worksheets("Sheet1").Select
Range("A63976").Paste
End If
Next i
end with
Update:
you could simplify a lot of this
Dim LastRow As Integer, i As Integer
Dim ws as worksheet
set ws = Workbooks("Workb1.xlsx").Sheets("Sheet1")
LastRow = ws.Cells(Rows.Count,"B").End(xlUp).Row
with ws
For i = 2 To LastRow
If Trim(Val(.Cells(i, 1))) = 848 Then
Range(.Cells(i, 2)).Copy _
destination:=Workbooks("destination.xlsx") _
.Worksheets("Sheet1").Range("A63976").Paste
End If
Next i
end with
This code will work fine. Check your cell that has 848 in it manually and make sure it is an integer.
Try this:
Dim LastRow As Integer, i As Integer
Dim ws4 As Worksheet
Set ws4 = Workbooks("Workb1.xlsx").Sheets("Sheet1")
LastRow = ws4.Cells(Rows.Count, "A").End(xlUp).Row
With ws4.Columns(1)
For i = 1 To LastRow
If .Cells(i).Value = 848 Then
Range(.Cells(i, 2), .Cells(i, 14)).Select
Selection.Copy
Workbooks("destination.xlsx").Activate
Worksheets("Sheet1").Select
Range("A63976").Select
Selection.PasteSpecial
End If
Next i
End With
EDIT:
Ok, I'm sure this is frowned upon, but this is how I would have solved the issue. It's nothing close to pro-code, but it gets the work done.
Range("A1").Select
Do Until ActiveCell.Value = ""
If ActiveCell.Value = 848 Then
Range(ActiveCell.Offset(0, 1).Address(False, False), ActiveCell.Offset(0, 14).Address(False, False)).Select
Selection.Copy
Workbooks("destination.xlsx").Activate
Worksheets("Sheet1").Select
Range("A63976").Select
Selection.PasteSpecial
End If
ActiveCell.Offset(1, 0).Select
Loop
If this code does not work, there's something else that's fishy. The code needs to be executed in the worksheet containing the list, which should be placed in column A and contain no blanks.
You can always change which sheet is selected by adding code.