Excel Visual Basic Run-time error '1004' when initializing a variable - vba

I am learning visual basic and this script I'm using is coming up with an error when I am initializing the variable i.
I'm not sure what the problem is but I am getting the error message:
Run-time error '1004': Application-defined or object-defined error
Here is my code:
Sub excelmacro()
Sheets("Sheet1").Select
Range("A1").Select
Sheets("Sheet2").Select
Range("B1").Select
i = 1
While i <> 10
If Len(ActiveCell.Value) > 1 Then
Sheets("Sheet1").Select
xname = Right(ActiveCell.Value, Len(ActiveCell.Value) - 6)
xsalary = Right(ActiveCell.Value, Len(ActiveCell.Offset(2, 0).Value) - 8)
xdesignation = Right(ActiveCell.Value, Len(ActiveCell.Offset(1, 0).Value) - 13)
Sheets("Sheet2").Select
ActiveCell.Value = xname
ActiveCell.Offset(0, 1).Value = xdesig
ActiveCell.Offset(0, 3).Value = xsalary
ActiveCell.Offset(1, 0).Select
Sheets("Sheet1").Select
ActiveCell.Offset(3, 0).Select
Else
i = 10
End If
Wend
End Sub

you do not need the variable i in your code anyway! just kick the line initializing i out.
The if statement in your loop that uses i is basically to escape the loop and can be shortened to:
While Len(ActiveCell.Value) > 1
Sheets("Sheet1").Select
xname = Right(ActiveCell.Value, Len(ActiveCell.Value) - 6)
xsalary = Right(ActiveCell.Value, Len(ActiveCell.Offset(2, 0).Value) - 8)
xdesignation = Right(ActiveCell.Value, Len(ActiveCell.Offset(1, 0).Value) - 13)
Sheets("Sheet2").Select
ActiveCell.Value = xname
ActiveCell.Offset(0, 1).Value = xdesig
ActiveCell.Offset(0, 3).Value = xsalary
ActiveCell.Offset(1, 0).Select
Sheets("Sheet1").Select
ActiveCell.Offset(3, 0).Select
Wend

This may be a good time to start practising the methods detailed in How to avoid using Select in Excel VBA macros.
Your code is repeatedly retrieving different lengths of the right-most characters from ActiveCell but using the length of the values from rows below the active cell to determine how many characters to retrieve. It seems that you should be retrieving the characters from the same cell that you are using to determine the length.
Sub excelmacro()
Dim i As Long, xname As String, xsalary As String, xdesignation As String
With Sheets("Sheet1")
For i = 1 To .Cells(Rows.Count, "A").End(xlUp).Row Step 3
If CBool(Len(.Cells(i, "A").Value)) Then
xname = Right(.Cells(i, "A").Value, Len(.Cells(i, "A").Value) - 6)
xdesignation = Right(.Cells(i + 1, "A").Value, Len(.Cells(i + 1, "A").Value) - 13)
xsalary = Right(.Cells(i + 2, "A").Value, Len(.Cells(i + 2, "A").Value) - 8)
With Sheets("Sheet2")
.Cells(Rows.Count, "B").End(xlUp).Offset(1, 0) = xname
.Cells(Rows.Count, "B").End(xlUp).Offset(0, 1) = xdesignation
.Cells(Rows.Count, "B").End(xlUp).Offset(0, 3) = xsalary
End With
End If
Next i
End With
End Sub
I've retained your use of a string variable for the salary although you may be better served by using a variable of type double and converting the text with a CDbl() wrapper. The second use of xdesig instead of xdesignation was corrrected.

Related

Trying to run this program, but getting error " compile error, wrong number of arguments, or invalid property assignment"

Private Sub CommandButton1_Click()
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
If Cells(i, 1) = "Wheat" Then
Range(Cells(i, 2), Cells(i, 3), Cells(i, 4)).Select
Selection.Copy
Workbooks.Open Filename:="C:\commodities\allcommodities-new.xlsm"
Worksheets("Sheet2").Select
erow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Cells(erow, 51).Select
ActiveSheet.Paste
ActiveWorkbook.Save
ActiveWorkbook.Close
End If
Next i
For i = 2 To LastRow
If Cells(i, 1) = "Feeder Cattle" Then
Range(Cells(i, 2), Cells(i, 3), Cells(i, 4)).Select
Selection.Copy
Workbooks.Open Filename:="C:\commodities\allcommodities-new.xlsm"
Worksheets("Sheet2").Select
erow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Cells(erow, 3).Select
ActiveSheet.Paste
ActiveWorkbook.Save
ActiveWorkbook.Close
End If
Next i
For i = 2 To LastRow
If Cells(i, 1) = "Corn" Then
Range(Cells(i, 2), Cells(i, 3), Cells(i, 4)).Select
Selection.Copy
Workbooks.Open Filename:="C:\commodities\allcommodities-new.xlsm"
Worksheets("Sheet2").Select
erow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Cells(erow, 67).Select
ActiveSheet.Paste
ActiveWorkbook.Save
ActiveWorkbook.Close
End If
Next i
end sub
NOTE: The code fails at the first "Range" command with a "compile error,
wrong number of arguments, or invalid property assignment" I can get the code to run with 2 cells definitions in the Range command.
While you can state range("B1, C1, D1") you cannot state range("B1", "C1", "D1") which is what you are trying to do.
If you actually want columns 2, 3 and 4 on row i then just use the first and the last like range("B1:D1")
Range(Cells(i, 2), Cells(i, 4)).Select
If the actual columns are a discontiguous group then use Union.
dim rng as range
set rng = union(Cells(i, 2), Cells(i, 4), Cells(i, 6))
rng.select
Please look into How to avoid using Select in Excel VBA macros.
Option Explicit
Private Sub CommandButton1_Click()
Dim i As Long, lastRow As Long, nextRow As Long
Dim wbACN As Workbook
lastRow = Range("A" & Rows.Count).End(xlUp).Row
Set wbACN = Workbooks.Open(Filename:="C:\commodities\allcommodities-new.xlsm")
For i = 2 To lastRow
Select Case LCase(Cells(i, 1).Value2)
Case "wheat"
Union(Cells(i, 2), Cells(i, 3), Cells(i, 4)).Copy _
Destination:=wbACN.Worksheets("Sheet2").Cells(Rows.Count, "AY").End(xlUp).Offset(1, 0)
Case "feeder cattle"
Union(Cells(i, 2), Cells(i, 3), Cells(i, 4)).Copy _
Destination:=wbACN.Worksheets("Sheet2").Cells(Rows.Count, "C").End(xlUp).Offset(1, 0)
Case "corn"
Union(Cells(i, 2), Cells(i, 3), Cells(i, 4)).Copy _
Destination:=wbACN.Worksheets("Sheet2").Cells(Rows.Count, "BO").End(xlUp).Offset(1, 0)
Case Else
'do notbhing
End Select
Next i
wbACN.Close savechanges:=True
End Sub

Replace range of data if target value already exists

The following script selects a range of data on one sheet and transfers the selection to another sheet.
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 6 To LastRow
If Cells(i, 1) <> "" And Cells(i, 21) = "OK" And Cells(i, 22) <> "Yes" Then
Range(Cells(i, 1), Cells(i, 4)).Select
Selection.Copy
erow = Worksheets("iForms").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Worksheets("iForms").Cells(erow, 1).PasteSpecial Paste:=xlPasteValues
If Cells(i, 1) <> "" Then Cells(i, 22).Value = "Yes"
If Cells(i, 22) <> "" Then Cells(i, 23).Value = Now
If Cells(i, 23) <> "" Then Cells(i, 24).Value = Environ("UserName")
ActiveWorkbook.Save
End If
Next i
I would now like to introduce a script which will replace the row of data on the target sheet if the value in column A already exists, but i'm not sure how to achieve this, any help is much appreciated.
Thank you in advance.
Public Function IsIn(li, Val) As Boolean
IsIn = False
Dim c
For Each c In li
If c = Val Then
IsIn = True
Exit Function
End If
Next c
End Function
dim a: a= range(destWB.sheet(whatever)..range("A1"),destWB.Range("A" & destWB.sheet(whatever).Rows.Count).End(xlUp)).value
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 6 To LastRow
if isin(a, Cells(i, 1) ) then
do whatever you want
else
If Cells(i, 1) <> "" And Cells(i, 21) = "OK" And Cells(i, 22) <> "Yes" Then
Range(Cells(i, 1), Cells(i, 4)).Select
Selection.Copy
erow = Worksheets("iForms").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Worksheets("iForms").Cells(erow, 1).PasteSpecial Paste:=xlPasteValues
If Cells(i, 1) <> "" Then Cells(i, 22).Value = "Yes"
If Cells(i, 22) <> "" Then Cells(i, 23).Value = Now
If Cells(i, 23) <> "" Then Cells(i, 24).Value = Environ("UserName")
ActiveWorkbook.save
End If
End If
Next i
I suggest using a Dictionary-Object which is most likely a Hash-Map. The advantage is that you can use the built in method Dictionary.Exists(Key) to check if the Dictionary already holds the specified value (Key).
Also you should not save the Workbook in every step of the iteration. It would be better (and faster) to only save the workbook after completing the copying of your whole data.
Additionally your If-Tests after copy-paste are not neccessary, because you are already checking for Cells(i,1)<>"" before copying so you don't have to check this again as it does not change.
The following code shows how to get your desired result:
Set dict = CreateObject("Scripting.Dictionary")
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 6 To LastRow
If Cells(i, 1) <> "" And Cells(i, 21) = "OK" And Cells(i, 22) <> "Yes" Then
If dict.Exists(Cells(i,1).Value) Then
'value already exists -> update row number
dict.Item(Cells(i,1).Value)=i
Else
'save value of column A and row number in dictionary
dict.Add Cells(i,1).Value, i
End If
Cells(i, 22).Value = "Yes"
Cells(i, 23).Value = Now
Cells(i, 24).Value = Environ("UserName")
End If
Next i
'finally copy over your data (only unique values)
For Each i In dict.Items
Range(Cells(i, 1), Cells(i, 4)).Select
Selection.Copy
erow = Worksheets("iForms").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Worksheets("iForms").Cells(erow, 1).PasteSpecial Paste:=xlPasteValues
Next i

Code works when running via editor but not when clicking hyperlink

The purpose of my macro is to simply take some information from one sheet and transfer it to another to prevent having to re-enter information. The code works perfectly when I run it via the VBA editor but results in in a Run-time error '1004': Applicaiton-defined or object-defined error when I try to run it via the hyperlink. I know the hyperlink is linked to the correct macro. What's going on?
Sub Insert_PCO_Row()
' Insert_PCO_Row Macro
' Inserts PCO information into COR log if COR number is entered in COR number column in "Sub Pricing" Worksheet.
Dim corNum As Range
Dim nextOpen As Range
Sheets("Sub Pricing").Select
Range("C3").Select
Set corNum = Sheet6.Range("A1:A1000")
Do Until Selection.Offset(0, -1) = ""
'Checks if COR # is entered in "Sub Pricing" tab OR if the COR # is already entered in "COR Log" tab.
If Selection.Value = "" Or Application.WorksheetFunction.CountIf(corNum, Selection.Value) > 0 = True Then
Selection.Offset(1, 0).Select
Else
Set nextOpen = Sheet6.Range("A9").End(xlDown).Offset(1, 0)
Selection.Copy
nextOpen.PasteSpecial xlPasteValues
Selection.Offset(0, 1).Copy
nextOpen.Offset(0, 1).PasteSpecial xlPasteValues
Selection.Offset(0, -2).Copy
nextOpen.Offset(0, 2).PasteSpecial xlPasteValues
Selection.Offset(0, -1).Copy
nextOpen.Offset(0, 3).PasteSpecial xlPasteValues
Selection.Offset(0, 7).Copy
nextOpen.Offset(0, 7).PasteSpecial xlPasteValues
Selection.Offset(1, 0).Select
End If
Loop
Sheets("COR Log").Select
End Sub
Try it without using .Select.
Option Explicit
Sub Insert_PCO_Row()
' Insert_PCO_Row Macro
' Inserts PCO information into COR log if COR number is entered in COR number column in "Sub Pricing" Worksheet.
Dim rw As Long, nrw As Long
With Worksheets("Sub Pricing")
For rw = 3 To .Cells(Rows.Count, 2).End(xlUp).Row
With .Cells(rw, 3)
If CBool(Len(.Value2)) And _
Not IsError(Application.Match(.Value2, sheet6.Columns(1), 0)) Then
nrw = sheet6.Cells(Rows.Count, "A").End(xlUp).Row + 1
sheet6.Cells(nrw, 1) = .Value
sheet6.Cells(nrw, 2) = .Offset(0, 1).Value
sheet6.Cells(nrw, 3) = .Offset(0, -2).Value
sheet6.Cells(nrw, 4) = .Offset(0, -1).Value
sheet6.Cells(nrw, 8) = .Offset(0, 7).Value
End If
End With
Next rw
End With
Worksheets("COR Log").Select
End Sub
Using the Range .Select method and relying on the Application.Selection and ActiveCell properties to identify the source and target of your operation is simply not reliable. In a similar vein, direct value transfer is more efficient than a Copy/PasteSpecial, Values operation and does not involve the clipboard.

"My code is not working"

I am trying to run the below code. But it is showing the error of Subscript out of range. When I tried to debug it, it is showing error in the 5 line: Range(“A1”).Select
While debugging, when I made the Sheet1 of 4th line as Sheet2, then it is not going on Sheet2.
Please help me run the code properly.
Sub excelmacro()
Application.ScreenUpdating = False
Sheets(“Sheet1”).Select
Range(“A1”).Select
Sheets(“Sheet2”).Select
Range(“A2”).Select
For i = 1 To 3
Sheets(“Sheet1”).Select
If Len(ActiveCell.Value) > 1 Then
Sheets(“Sheet1”).Select
Xname = Right(ActiveCell.Value, Len(ActiveCell.Value) - 6)
Xdesig = Right(ActiveCell.Offset(1, 0).Value, Len(ActiveCell.Offset(1, 0).Value) - 13)
Xsalary = Right(ActiveCell.Offset(2, 0).Value, Len(ActiveCell.Offset(2, 0).Value) - 8)
Sheets(“Sheet2”).Select
ActiveCell.Value = Xname
ActiveCell.Offset(0, 1).Value = Xdesig
ActiveCell.Offset(0, 2).Value = Xsalary
ActiveCell.Offset(1, 0).Select
Sheets(“Sheet1”).Select
ActiveCell.Offset(3, 0).Select
Else
i = 10
End If
i = i - 1
Next
Application.ScreenUpdating = True
End Sub
The quotation marks are oddball and create an error, but even after changing to 'normal' quoates there is a Subscript out of range error:
Instead of using Sheets, try Worksheets:
Worksheets("Sheet1").Select
To summarize my comments:
The double-quotes in the original code are oddly formatted. Use Notepad or the VBA IDE to replace them with appropriate plain text double quotes.
Be sure to declare your variables before using them if Option Explicit is turned on. Also just a good practice to follow even if it were not on.
(To be updated when I have more time this evening) Avoid making selections and usingActiveCell/ActiveSheet references.
With minor changes to your code it should look like this:
Sub excelmacro()
Dim i As Double, _
Xname As String, _
Xdesig As String, _
Xsalary As String
Application.ScreenUpdating = False
Sheets("Sheet1").Select
Range("A1").Select
Sheets("Sheet2").Select
Range("A2").Select
For i = 1 To 3
Sheets("Sheet1").Select
If Len(ActiveCell.Value) > 1 Then
Sheets("Sheet1").Select
Xname = Right(ActiveCell.Value, Len(ActiveCell.Value) - 6)
Xdesig = Right(ActiveCell.Offset(1, 0).Value, Len(ActiveCell.Offset(1, 0).Value) - 13)
Xsalary = Right(ActiveCell.Offset(2, 0).Value, Len(ActiveCell.Offset(2, 0).Value) - 8)
Sheets("Sheet2").Select
ActiveCell.Value = Xname
ActiveCell.Offset(0, 1).Value = Xdesig
ActiveCell.Offset(0, 2).Value = Xsalary
ActiveCell.Offset(1, 0).Select
Sheets("Sheet1").Select
ActiveCell.Offset(3, 0).Select
Else
i = 10
End If
i = i - 1
Next
Application.ScreenUpdating = True
End Sub
I think this is what you're trying to do:
Sub excelmacro()
Dim lastrowinSheet1 As Long
Dim cellinSheet2 As Range
Dim rCell As Range
Dim x As Long
With ThisWorkbook
'Set a reference to cell A1 on Sheet2.
Set cellinSheet2 = .Worksheets("Sheet2").Range("A1")
With .Worksheets("Sheet1")
'This will return the last row number containing data in column A.
lastrowinSheet1 = .Cells(Rows.Count, 1).End(xlUp).Row
'Now loop through each cell in column A of sheet1.
For x = 1 To lastrowinSheet1
If Len(.Cells(x, 1)) > 1 Then
cellinSheet2.Value = Right(.Cells(x, 1).Value, Len(.Cells(x, 1).Value) - 6)
cellinSheet2.Offset(, 1) = Right(.Cells(x, 1).Offset(1).Value, Len(.Cells(x, 1).Offset(1).Value) - 13)
cellinSheet2.Offset(, 2) = Right(.Cells(x, 1).Offset(2).Value, Len(.Cells(x, 1).Offset(2).Value) - 8)
Set cellinSheet2 = cellinSheet2.Offset(1)
x = x + 2
End If
Next x
End With
End With
End Sub
I tried taking apart your code - I think this is what it's doing:
Sub excelmacro1()
'Stop the screen flicker.
Application.ScreenUpdating = False
'Select cell A1 on Sheet1.
Sheets(“Sheet1”).Select
Range(“A1”).Select
'Select cell A2 on sheet 2.
Sheets(“Sheet2”).Select
Range(“A2”).Select
For i = 1 To 3
'Select Sheet1 again.
Sheets(“Sheet1”).Select
'If the length of text in the ActiveCell is greater than 1 character then
'execute the lines up to ELSE.
If Len(ActiveCell.Value) > 1 Then
'Select Sheet1 yet again.
Sheets(“Sheet1”).Select
'Hope the value in the ActiveCell isn't longer than 6 digits, or it will error out.
'Take all characters from the ActiveCell except the last 6.
Xname = Right(ActiveCell.Value, Len(ActiveCell.Value) - 6)
'Take all characters from the ActiveCell except the last 13.
Xdesig = Right(ActiveCell.Offset(1, 0).Value, Len(ActiveCell.Offset(1, 0).Value) - 13)
'Take all characters from the ActiveCell except the last 8.
Xsalary = Right(ActiveCell.Offset(2, 0).Value, Len(ActiveCell.Offset(2, 0).Value) - 8)
'Select Sheet2.
Sheets(“Sheet2”).Select
'Place the values in ActiveCell and the two columns to the right.
ActiveCell.Value = Xname
ActiveCell.Offset(0, 1).Value = Xdesig
ActiveCell.Offset(0, 2).Value = Xsalary
'Select the next row down.
ActiveCell.Offset(1, 0).Select
'Active Sheet1 again.
Sheets(“Sheet1”).Select
'Select the cell 3 rows down from the previous row.
ActiveCell.Offset(3, 0).Select
Else
'If the lengh of text in the ActiveCell is 1 character or less then set the value of i to 10.
i = 10
End If
'Remove 1 from i.
i = i - 1
Next
Application.ScreenUpdating = True
End Sub

Issue with For Loops

why does this not work? Basically i have a list in a single cell i want to split strings ending in "sec" and ones that don't by copying them into different columns.
Sub test_if()
For i = 1 To 300
Cells(i, 2).Select
If Right(Cells(i, 2), 3) = "SEC" Then
ActiveCell.Select
Selection.Copy
Cells(i, 3).Select
ActiveSheet.Paste
End If
If Right(Cells(i, 2), 3) <> "SEC" Then
ActiveCell.Select
Selection.Copy
'Cells(i, 4).Select
ActiveCell.Offset(i - 1, 2).Select
ActiveSheet.Paste
End If
Next i
Cells(1, 1).Select
End Sub
Try this one:
Sub test_if()
Dim i As Integer
For i = 1 To 300
With Cells(i, 2)
If UCase(Right(.Value, 3)) = "SEC" Then
.Offset(, 1).Value = .Value
Else
.Offset(i - 1, 2).Value = .Value
End If
End With
Next i
End Sub
and also read, please, how to avoid using Select/Active statements