In my VBA code, I am attempting to do the following:
Set the Active Cell to C11
Add the number 1 to an id
Prompt the user for a name and enter that in the cell to the right
Go to the next row & repeat.
However, the number that is entered is another one, not a 2, 3, 4....
Instead, I get the following:
1 Name 1
1 Name 2
1 Name 3
and I want:
1 Name 1
2 Name 2
3 Name 3
Here is the code, what am I missing?
Sub AddToSheet()
Dim id As Integer
Dim name As String
Worksheets("sheet1").Activate
ActiveCell.Range("C11").Select
For Each mycell In Range("C11:C20")
id = mycell.Select
ActiveCell.Value = 1
id = id + 1
name = mycell.Offset(0, 1).Select
name = InputBox("what is the film?")
ActiveCell.Value = name
Next mycell
End Sub
It's not what you're missing, it's what you are getting wrong - some pointers:
1) There is rarely (dare I say, never) a need to use .Select in Excel VBA, you can access an object's properties directly without selecting the actual object. This is generally considered bad practice.
2) id = mycell.Select is not a valid statement, the .Select method merely sets focus to an object(s) it is not used to return a value.
3) ActiveCell.Value = 1 <-- This is where you are going wrong as far as your question is concerned
4) Your code increments the value of id with each loop, but you do not actually use this value for anything - another hint at why it's not working as you expected.
5) Try and use indentation on your code, this will make it much easier for you (and others) to follow the logic of your code and help to ensure you have closed all 'block' statements.
Try this code instead:
Sub AddToSheet()
Dim i As Integer
For i = 11 To 20
Range("C" & i & ":D" & i).Value = Array(i - 10, InputBox("What is the film?"))
Next i
End Sub
This accesses the .Value method of the Range object without actually selecting or activating it, and so we skip a couple of lines of code straight away. Secondly - I've used an Array to assign the values so that we can do it all in one line of code - this is nothing groundbreaking and you won't see any difference in speed/performance but it's hopefully something for you to look at and possibly manipulate for your own uses in the future.
Related
I am new at using VBA and I am trying to do something that seems "simple." I have my VBA code generate a string (CP20210100001) and I want my for loop to check if that string has already been used in that column. If already used, generate the next in the serial until the next unique value in the serial has been generated.
My boss wants to paste a different ID occasionally in the column and this disturbs the code. My code looks at the last row and adds one to the String + serial. This will result in duplicates.
I figured out through much googling to get the code to check the current value for duplicates but I can't figure out how to get it to check for future IDs in the series until it comes across a unique value.
Below you can see my column. I had 10 successful submission and then my boss pasted 3 rows. With my VBA the next generated ID would be CP20210200004 but last part of the code found it as duplicate so it added 1 and inputted CP20210200005. Ideally the VBA should for loop until the next in the serial shows up. In this case CP20210200011. This way no matter how many times my boss disrupts my table, my ID sequence stays in tact.
**Reference ID**
CP20210100000
CP20210200001
CP20210200002
CP20210200003
CP20210200004
CP20210200005
CP20210200006
CP20210200007
CP20210200008
CP20210200009
CP20210200010
JS20210200001
JS20210200002
JS20210200003
CP20210200005
Below is the the VBA
#Timestamp is part of the String + Serial Combo
Timestamp = Format(Year(Date)) + Format(Month(Date), "00")
#I found this online. Essentially if A2 is blank then input CP + Timestamp + 00001 (CP20210100001)
#It looks at the last row to find the old value (OVAL) and generate the new value (NVAL)
If Sheets(ws_output).Range("A2") = "" Then
Sheets(ws_output).Range("A2").Value = "CP" & Timestamp + 1
Else
lstrow = Sheets(ws_output).Cells(Rows.Count, "A").End(xlUp).Row
Oval = Sheets(ws_output).Range("A" & lstrow)
NVAL = "CP" & Timestamp & Format(Right(Oval, 4) + 1, "00000")
#Here I am trying to see if NVAL is a duplicate value. If so add one to the serial.
Count = Application.WorksheetFunction.Countif(Sheets(ws_output).Range("A2:A100000"), NVAL)
Dim Cell As Range
For Each Cell In Sheets(ws_output).Range("A2:A100000")
If Count > 1 Then
NXVAL = NVAL
Else
NXVAL = "CP" & Timestamp & Format(Right(NVAL, 4) + 1, "00000")
End If
Next
Please please please help.
EDIT
I Should clarify that all of this is triggered on a form. The module is connected to a submit button. Once the button is pressed all the values in the form write to a separate sheet. Reference ID is the only part that isn't on the form. Essentially once the button is pressed, it triggers the query to write the next available reference ID. The next line in the query is
Sheets("Sheet2").Cells(next_row, 1).Value = NXVAL
I need the new Reference ID to equal a variable.
Your code seems to give you much grief and little comfort. The reason is that you didn't take a strictly logical approach. The tasks are ...
Find the last used number. I suggest to use VBA's own Find function.
Insert the next number. It consists of prefix, Date and serial number.
So, you arrive at code like this:-
Sub STO_66112119()
' 168
Const NumClm As Long = 1 ' 1 = column A
Dim Prefix As String
Dim LastNumber As Long
Dim Fnd As Range ' search result
Prefix = "JS" ' you could get this from an InputBox to
' enable numbering for other prefixes
With Columns(NumClm)
On Error Resume Next ' if column A is blank
Set Fnd = .Find(What:=Prefix, _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
Lookat:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
End With
LastNumber = Val(Right(Fnd.Value, 5))
On Error GoTo 0
Cells(Rows.Count, NumClm).End(xlUp).Offset(1).Value = Prefix & Format(Date, "yyyymm") _
& Format(LastNumber + 1, "00000")
End Sub
You need to spend a moment on preparation, however.
Define the column to work in. I put this in the Const NumClm. It's at the top of the code so as to make maintenance easier (won't need to dig in the code to make a change).
My code shows Prefix = "JS". You want to change this to "CP". I inserted "JS" to show that you could use any prefix.
The above code will continue counting up in a new month and even a new year. If you want to start each year with a new series just change the way you handle the found previous. The Find function will return the cell where the prefix was last used. You might further examine that cell's value.
Hi I am writing Excel VBA code. I just wanted to do subtraction for this kind of table
But I can't figure out how to do that using VBA. Is the code below correct?
Sub OperationO()
Dim OE As Integer
Dim i As Integer
For i = 3 To Range("F6")
Cells(6, i).Value = Cells(2, i).Value - Cells(4, i)
Next i
End Sub
You should really use formulas for something like this, but if you insists on VBA, here it goes.
Whenever you write code for VBA or any similar languages, read what you are writing, what it should/needs to do, as you read it out loud many times the errors pop up. Think of the comments below as "me reading as I write."
Sub OperationO()
'Initiate a Variable type Integer for number storage
Dim OE as Integer
'Initiate another variable same type to use in the loop
Dim i as Integer
'Start a loop from 3 to 6 (because these are the columns you are working with)
For i = 3 to 6
'Set the value in Column "i" on Row 6 to the value in Row 2 minus Row 4 in the same column
'Now here is the thing, when you subtract a negative number, you are adding it, crazy math rules i know, so if the number is negative, you need to Add instead.
Cells(6, i).Value = (Cells(2, i).Value + Cells(4, i).Value)
'If both cells don't contain a number, this will fail, additional checks may help, like IsNumber
Next i
'Its the end of the Sub and you never used the Variable OE, it was declared for nothing.
End Sub
I have never coded in VBA before and am trying to teach myself based off Youtube videos right now which is proving difficult. I am attempting to do a for loop that deletes a row if it does not equal the Part Number, and if the part number is correct, I want the loop to do nothing and move on. I have been typing up random lists of numbers to test my code on, but when I run it, every single row is deleted (even the ones with the correct part number). Ultimately, when I run this on the real data the part number will be a combination of letters and numbers as well as a dash, so I should be storing the Part Number as a string variable correct? Any advice?
Sub CodingPrac()
Dim PartNum As String
PartNum = InputBox("Enter the Part Number", "Part Number", "Type value here")
lastrow = ThisWorkbook.Sheets(2).Cells(Rows.Count, 1).End(xlUp).Row
For i = lastrow To 1 Step -1
If Cells(i, 1).Value = "PartNum" Then
Else
ThisWorkbook.Sheets(2).Rows(i).EntireRow.Delete
End If
Next i
End Sub
Replace:
If Cells(i, 1).Value = "PartNum" Then
with:
If Cells(i, 1).Value = PartNum Then
you need the value of the variable, not a string.
EDIT#1:
Your code (as posted) would work if column A was like:
I have just started to work on Excel macros.
Please let me know what is wrong in the following code:
Sub color_red()
Dim range As range
For R = 1 To 20
If Cells(R, 1).Value = 1 Then range(R, R).Interior.ColorIndex = 3
Next R
End Sub
Error message displayed:
Object variable or with block variable not set
Thanks in advance for your guidance.
You can't use variable name which is any VBA: key word, function, object name, collection name, etc. Try to change your variable name from range into rngTable.
EDIT after additional information written as comments in different areas of that post:
change your if code line into:
If Cells(R,1).Value = 1 Then Cells(R,1).EntireRow.Interior.ColorIndex =3
which will colour all sheet columns in row R. To colour certain range, e.g. in 10 columns you could use this line instead of your if:
If Cells(R,1).Value = 1 Then Cells(R,1).Resize(1,10).Interior.ColorIndex =3
I see that you are still having problem with this code. Please try this simple subroutine, this might be what you need:
Public Sub ColorRowIf()
Dim r As Long
For r = 1 To 20
If Cells(r, 1).value = 1 Then
Cells(r, 1).EntireRow.Interior.ColorIndex = 3
End If
Next r
End Sub
Please also note that using 'Cells()' is not a good way to go, but I have included it for simplicity (as asked). 'Cells()' will always refer to the active sheet cells which might not always be the case. So, instead you should use full reference of the sheet (by code name method) -- so in this example it should say for e.g.: Sheet1.Cells(r,1).Value = 1. Also, remember Sheet1 is not the tab name, its the code name that you see in project window.
#KazJaw is correct, you cannot use a key word as a variable name. But the range or rngTable variable is still used before it is set.
You could still use a Range variable, but why don't you use the same way of addressing as in the if statement?
If Cells(r, 1).Value = 1 Then Cells(r, 1).Interior.ColorIndex = 3
Otherwise you would have to set the range object before you use it:
Set rngTable = Cells(r, 1)
I feel like a lot of people gleaned over the fact your variable 'R' is not defined other than 666bytes.
Declaring the variables you are going to be using is an important thing to do in order to get code to work.
Instead of range you can use the Cells function. You have to refer the WorkSheet for using range. Since nothing is mentioned ,its throwing Object variable or with block variable not set.
Sub color_red()
Dim r As Integer
For r = 1 To 20
If Cells(r, 1).Value = 1 Then Cells(r, r).Interior.ColorIndex = 3
Next r
End Sub
I'm trying to write a function that merges multiple rows of text in a column into a single cell based on a pre determined count. My goal is to generate a flexible function to aid in compiling / interperting large quantaties of data. The code I've written returns #NAME? and I cant figure out where the error is. My code is as follows:
Function vmrg(countref As Integer, datref As Integer) As String
If IsEmpty(ActiveCell.Offset(0, -countref)) Then % check if cell containing count is blank
vertmerge = "N/A" % if blank, state N/A
Else
Dim datlst(0 To ActiveCell.Offset(0, -countref).Value - 1) As String
Dim i As Integer
For i = 0 To ActiveCell.Offset(0, -countref).Value - 1
datlst(i) = ActiveCell.Offset(i, -datref).Text %fill array with data
End
vertmerge = datlst(0)
For i = 1 To ActiveCell.Offset(0, -countref).Value - 1 % merge array to a single string
vertmerge = vertmerge & ", " & datlst(i)
End
End
End Function
I have matlab and some C++ experience but this is the first time I've used VBA so my syntax is probably odd in some areas and wrong in others. Ideally I would like to reference the cells where the data and count info are stored, but for now I'm hoping to correct my syntax and set a jumping off point for further development of this function. Any reccomendations are appreciated.
Code Rev_1: I still have an output of #NAME? but I think I've corrected(?) some of the issues
Function vertmerge(countref As Range, datref As Integer) As String
If IsEmpty(countref) = True Then
vertmerge = "NA"
Else
Dim datlst(0 To countref.Value - 1) As String
Dim i As Integer
For i = 0 To countref.Value - 1
datlst(i) = countref.Offset(i, datref).Text
Next i
vertmerge = datlst(0)
For i = 1 To countref.Value - 1
vertmerge = vertmerge & ", " & datlst(i)
Next i
End
End Function
You are doing some dangerous things here!
First - you are referencing "ActiveCell" from inside a function; but you have NO IDEA what cell will be active when the function runs! Instead, pass the target cell as a parameter:
=vmrg("B6", 5, 6)
and change your function prototype to
Function vmrg(r as Range, countref as Integer, datref as Integer)
Now you can reference things relative to r with
r.Offset(1,2)
etc.
Next - you are never assigning anything to vmrg. In VBA, the way a function returns a value is with (in this case)
vmrg = 23
You are assigning things to a variable called vertmerge - but that is not the name of your function. At least add
vmrg = vertmerge
Just before returning. That might do it. Without a full sample of your spreadsheet I can't help you more.