I want code to check one column of data for a condition ie: Range Qualification. If they are required to go the the Range the value will be "REQ" if they are not the values will be "E", "S", "M", and "NR". I use [select case] to check the condition. At the start of the select case I get this error.
I am not sure if I am making the sell reference right or not. After the array is populated with names from another column, I then go through and remove the empty elements from the array and then display all elements of the array in a msgbox. Below is the code I used:
'Declares total number of personnel as integer
Dim total As Integer
total = Worksheets("MASTER").Range("C4").Value
'Declares single element array with personnel full names
ReDim names(total) As String
'Loops through the array checking to see if personnel have qualified on the Rifle Range
For i = (1 + 6) To (total + 6)
Select Case Worksheets("MASTER").Range(Cells(i, 23)).Text
Case "REQ"
names(i - 6) = Worksheets("MASTER").Range(Cells(i, 7)).Value
Case "NR"
names(i - 6) = vbNullString
Case "E"
names(i - 6) = vbNullString
Case "S"
names(i - 6) = vbNullString
Case "M"
names(i - 6) = vbNullString
End Select
Next
'Declares a new array to remove blank elements from the orignal array
ReDim msgnames(LBound(names) To UBound(names))
'Loops through new array removing empty elements
For i = LBound(names) To UBound(names)
If names(i) <> vbNullString Then
x = x + 1
msgnames(x) = names(i)
End If
Next
'Displays every element of the array
For i = LBound(msgnames) To UBound(msgnames)
msg = msg & msgnames(i) & vbNewLine
Next
'Declares COMP, NOTCOMP, REQ and NOTREQ variables
Dim COMP As String
Dim NOTCOMP As String
Dim REQ As String
Dim NOTREQ As String
'Adds a comment to the bottom of the Message Box
MsgBox msg, vbOKOnly, "Rifle Range"`
You have the wrong syntax for your range.
Change this:
Select Case Worksheets("MASTER").Range(Cells(i, 23)).Text
to this:
Select Case Worksheets("MASTER").Cells(i, 23).Value2
One other thing -- you should use .value or .value2 instead of .text unless you have a very specific reason for using .text. See Charles Williams' article for an excellent analysis of the three properties: TEXT vs VALUE vs VALUE2 - Slow TEXT and how to avoid it.
Related
I have some ComboBoxes on my FORM. One of them have items as a result of SQL request from field PG (cbPG.RowSource = "SELECT DISTINCT W_report.PG FROM W_report WHERE ......) The size of the field is byte.
After reqest
User can select one of the variant or can list several comma-separated (2,4,5,7,11,13).
Correct value
The resulting ComboBox.value is used in a procedure similar to selecting pages for printing. Everything works correctly until changes are made to the event handler of cbPG. Then the values are automatically rounded (if one comma)
wrong value
or an error "The entered value is not appropriate for this field" occurs (if a few commas) and I have to copy cbPG from the backup because I can't find a property that changes format of cbPG.value to byte.
Here is part of program that use my ComboBox
Public Function MnogoListov(str As String) As String
Dim i, j As Integer
Dim res As String
Dim listArr() As String
res = ""
ReDim listArr(Len(str)) As String
For i = 1 To Len(str)
If Mid(str, i, 1) <> "," And Mid(str, i, 1) <> "." Then
listArr(j) = listArr(j) & Mid(str, i, 1)
Else
j = j + 1
End If
Next
For i = 0 To j
If i = 0 Then
res = listArr(i)
Else
res = res & " OR W_report.PG = " & listArr(i) End If
Next
MnogoListov = res
End Function
You can't do that. A combobox is for selecting one value from several.
So, either use a multi-select listbox or a simple textbox where you - similar to selecting pages for printing - parse the inputted values to obtain the sequence (list) of items (pages).
I have the following data set, which contains duplicates.
values:
2880CR-20.36KX53305DECOAK2015
F05572-CN48517OCTOAK2016
F05572-CN48517DECOAK2016
F05572-CN48517NOVOAK2015
F05572-CN48517NOVOAK2015(duplicate)
F05572-CN48517DECOAK2015
F05573-CN48517JANOAK2016
F05573-CN48517FEBOAK2016
F05573-CN48517JANOAK2015
F05573-CN48517FEBOAK2015
F05573-CN48517MAROAK2015
F05573-CN48517APROAK2015
F05573-CN48517APROAK2015(duplicate)
I am trying to create a macro that will look at the values in column A, from A2:A (count of rows in column), and return a list of the duplicate values contained in the string declared "strMyDupList". Basically, if there is atleast 1 duplicate, the msgbox will pop up and the new sheet created with the columns address and values and I am trying to list out all the values seperated my a comma VERTICALLY, instead of horizontally across the sheet. so like:
Address value
$A$5 F05572-CN48517NOVOAK2015
$A$13 F05573-CN48517APROAK2015
my code is :
If strMyDupList <> "" Then
MsgBox "The following entries have been used more than once:" & vbNewLine & strMyDupList
Worksheets.Add.name = name
Worksheets(name).Range("A1").Value = "Location"
Worksheets(name).Range("B1").Value = "Value"
' Worksheets(name).Range("A2:C2").Value = Split(strMyDupList, ",")
Worksheets(name).Range("B4:B6") = Split(Application.WorksheetFunction.Transpose(strMyDupList), ",")
The results are that I am able to get the values tranposed from horizontal to vertical, however, with this code, it is only returning the FIRST VALUE in the list of values in the string, so it's returning:
Address value
$A$5 F05572-CN48517NOVOAK2015
$A$5 F05572-CN48517NOVOAK2015 (should be F05573-CN48517APROAK2015)
I've seen the UBound with Resize could work but I have no idea how the syntax works or is used. Can someone assist?
Thank you
Here is a complete example of how to leave duplicates out of your information.
Essentially, it sorts all of your information. Therefore, when you sort you'll get the consecutive value which would be itself if it was a dupe.
It uses a .NET feature, System.Collections.ArrayList, that was in 2.0 & 3.5 so that has to be installed on your machine. Usually it already is but it may not be. You can turn it on through Programs & Features.
Sub StringArrayDupeChecker()
Dim var As Variant
Dim holder As String
Dim strMyList() As String
Dim myDupeData As Variant
Dim str As String
str = "one,two,three,three,three,four,five,five"
strMyList = Split(str, ",")
holder = ""
Set var = CreateObject("System.Collections.ArrayList")
Set myDupeData = CreateObject("System.Collections.ArrayList")
For Each i In strMyList
var.Add (i)
Next i
var.Sort
For Each j In var
If Not j = holder Then
'do your stuff
str = "notDupe"
Else
myDupeData.Add(j)
End If
holder = j
Next j
End Sub
I use create Bills Of Materials in Excel before importing into another program and I'm trying to sort these lists by Reference Designation which consist of prefix page number 1-200, followed by device type A-ZZ, followed by device number (ID) on that page 1-99, followed by letter which represents part of device A-Z (if that device consists of multiple parts). Here are examples of RefDes:
1Q1
1S6
1S7
1T1
1VENT
1X1
1X2
1Y1
1Z1-A
1Z1-B
2A1-A
2A1-B
2A1-C
22M1
2QF1
2RB1
2Z1-A
2Z1-B
13A1-A
13A1-B
13A1-C
3A2-A
3A2-B
3A2-C
I want it sorted first by Device type A-ZZ, then by device ID, then device part, then by page.
1A1A
....
1A1Z
1A2A
....
1A2Z
2A1A
....
2A1Z
....
200A99Z
1B1A
....
200ZZ99Z
So that the list above is sorted like this:
2A1-A
2A1-B
2A1-C
3A1-A
3A1-B
3A1-C
13A1-A
13A1-B
13A1-C
22M1
1Q1
2QF1
2RB1
1S6
1S7
1T1
1VENT
1X1
1X2
1Z1-A
1Z1-B
2Z1-A
2Z1-B
So far I have been able to sort by page then by device type and even then it sorts wrong: 1A-1ZZ, then 1xA-1xZZ, then 2A-2ZZ, then 2xA-2xZZ, etc... I can get rid of the dash (-) when I build the BOM.
I don't know if this is the most efficient way of doing it, but based on how your BOMs are constructed, it might be easier to split out the data into temporary columns, then sort it, then delete the columns.
Your sorting requirements and order seem too complex to do it any other way that I know of.
Sub SortBOMS()
Dim workingRange As Range
Dim workingCell As Range
Dim pageNumber As String
Dim deviceType As String
Dim deviceID As String
Dim devicePart As String
Dim i As Integer
Application.ScreenUpdating = False
'Obtains the full list. (Assumes you have no data after the 1millionth row)
Set workingRange = Range("A1:A" & Range("A1000000").End(xlUp).Row)
For Each workingCell In workingRange.Cells
'Builds the page number
pageNumber = ""
For i = 1 To 3 'Used 3 since 200 is 3 characters
If IsNumeric(Mid(workingCell.Text, i, 1)) Then
pageNumber = pageNumber & Mid(workingCell.Text, i, 1)
Else
Exit For 'Exits as soon as encounters a letter
End If
Next i
'Writes the value after converting it to an integer
Range("B" & workingCell.Row).Value = CInt(pageNumber)
'Builds the device type
deviceType = ""
For i = 1 To 2 'Used 2 since ZZ is 2 characters
If Not (IsNumeric(Mid(Split(workingCell.Text, pageNumber)(1), i, 1))) Then
deviceType = deviceType & Mid(Split(workingCell.Text, pageNumber)(1), i, 1)
Else
Exit For 'Exits as soon as encounters a number
End If
Next i
'Writes the value
Range("C" & workingCell.Row).Value = deviceType
'Builds the device ID
deviceID = ""
For i = 1 To 2 'Used 2 since 99 is 2 characters
If IsNumeric(Mid(Split(workingCell.Text, pageNumber & deviceType)(1), i, 1)) Then
deviceID = deviceID & Mid(Split(workingCell.Text, pageNumber & deviceType)(1), i, 1)
Else
Exit For 'Exits as soon as encounters a letter or a dash
End If
Next i
'Writes the value after converting it to an integer
On Error Resume Next
Range("D" & workingCell.Row).Value = CInt(deviceID)
On Error GoTo 0
'Builds the device part
devicePart = ""
If InStr(1, workingCell.Text, "-", vbTextCompare) > 0 Then
devicePart = Split(workingCell.Text, "-")(1)
End If
'Writes the value
Range("E" & workingCell.Row).Value = devicePart
Next workingCell
'Clean up
Application.ScreenUpdating = True
Set workingRange = Nothing
Set workingCell = Nothing
End Sub
After this runs, you should be able to sort the way you want to. Also, to get the results you want sort in this order, not the order you mentioned in the post:
Device Type
Page Number
Device ID
Device Part
This is what my cells look like:
This is my code, I'll explain it below.
Sub Macro1()
Dim product as String
Dim group as Long
Dim recordno as Long
dim pol_number as Long
dim plan_name as Long
product = "corp"
group = 1
recordno = 1
pol_number = 1
plan_name = "TTT"
Range("A2").Select
For i = 1 to 5
ActiveCell.Value = Selection.End(xlUp).Value
ActiveCell.Offset(0,1).Select
Next i
End Sub
I want to fill in all of the cells with the variable values. I understand that variables are not case sensitive, and I understand that the code I have will just fill the cell with the text in the upmost cell of the column, but I don't know if there is a function that would take the text of the top cell and convert it to a variable. Is that possible?
Try this to go from variables to cells
Dim values as Variant
'Array 0 to 4
values = Array(product,group,recordno,pol_number,plan_name)
Range("A2").Resize(1,5).Value2 = values
The reverse is
Dim values as Variant
'Array 1 to 5
values = Range("A2").Resize(1,5).Value2
product = values(1,1)
group = values(1,2)
recordno = values(1,3)
pol_number = values(1,4)
plan_name = values(1,5)
If you do something like
someCell.Value = someOtherCell.Value
and someOtherCell.Value is "product" then someCell won't be filled with what you have saved in the variable product but with "product" (I included the quotation marks to emphasize that's it's a string). That's a good thing because otherwise it would mess your code up if you accidentally put in the name of some random variable in your code.
If your requirements are like this:
You have values for PRODUCT etc that you write to write in the row below PRODUCT etc.
The headers are not always in the same order.
You might want to add new variables later on without too much fuss.
Them some kind of keyed list might be what your looking for. That means that rather than referencing the variable by a numerical index, you can reference them using names.
If the order is fixed, you might be better of just using an array where item 1 is the product name, item 2 is the group number etc, like ja72 and Sgdva suggested.
However, if you still want to reference the variables by name, you could use a collection:
Dim coll As New Collection
With coll
.Add "corp", "product"
.Add 1, "group"
.Add 1, "recordno"
'...
End With
Then instead of selecting cells and referencing ActiveCell you should reference the cells directly (using selections and ActiveCell can be avoided most of the times and slows down the macro and can even cause unnecessary errors)
For i = 1 To 5
Cells(2, i).value = coll(Cells(1, i).value)
Next i
An alternative to a collection is a dictionary which offers an easy way to check if a key exists (with a collection you have to catch the error)
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
With dict
.Add "product", "corp"
.Add "group", 1
.Add "recordno", 1
'...
End With
Now you can check if the entry exists first so it won't throw an error:
For i = 1 To 5
If dict.Exists(LCase(Cells(1, i).value)) Then 'note that the dictionary keys are case sensitive
Cells(2, i).value = dict(LCase(Cells(1, i).value))
Else
MsgBox "Entry for " & LCase(Cells(1, i).value) & " not found!"
End If
Next i
Note that when you use dict("somekey") and the entry "somekey" doesn't exist, it won't throw an error but add an empty entry.
Why not an array and then loop through the elements as needed?
Dim ArrayTitles() As Variant 'since strings and numbers are mixed
ReDim Preserve ArrayTitles(5)
ArrayTitles(1) = "corp"
ArrayTitles(2) = 1
ArrayTitles(3) = 1
ArrayTitles(4) = 1
ArrayTitles(5) = "TTT"
Range("A2").Select
For i = 1 To 5
MsgBox (ArrayTitles(i))
I'm thinking what you are trying to accomplish can be solved in this way
for j = 1 to 6 'Or whatever your last column happens to be
if UCase(cells(1, j)) = "PRODUCT" then
if ActiveCell.Column = j then
ActiveCell.Value = "corp"
end if
end if
next j
Something like that?
I'm trying to get some data I input with another macro into a 2-dimensional array so I can then apply a function to that data, but no matter what I try I keep getting errors. The data includes strings and numbers. I could always just reference the cells and forget about the array, but that complicates the function. Here's my code:
(Declarations)
Dim nLiens As Byte, nCreditors As Byte
Dim SecurityV As Currency, ASecurityV As Currency
Const adjuster = 0.9
(Relevant subs)
Public Sub VariableDeclaration()
nLiens = InputBox("Enter number of liens in security")
nCreditors = InputBox("Enter number of creditors")
SecurityV = InputBox("Enter security full value")
ASecurityV = adjuster * SecurityV
Call ODebt
End Sub
Sub ODebt()
'
'(...)
'
Dim oDebt() As Variant
ReDim oDebt(1 To nCreditors + 1, 1 To nLiens + 1)
Dim rg As Range
Set rg = Range(Cells(1, 1), Cells(nCreditors + 1, nLiens + 1))
oDebt = rg.Value
MsgBox (oDebt)
'>>> ERROR: type mismatch
Call SAllocation
End Sub
I've tried other alternatives, such as setting the content cell by cell with two 'For' loops and LBound and UBound, but nothing seems to work.
You are getting your error not while filling, but at displaying the array.
It is not possible to just Msgbox an array, since Msgbox expects a String argument. You can, in the other hand, display specific positions (e.g. oDebt(1,1)).
If you want to have a look at all of its contents, either use debug mode and the Local window, or print it to some unused cells.
I would copy the values from the datasheet this way:
Dim oDebt As Variant
Dim rg As Range
Set rg = Range(Cells(1, 1), Cells(nCreditors + 1, nLiens + 1))
oDebt = rg ' get data from sheet
'... do calculations with oDebt array
rg = oDebt ' put data on sheet
In words: you dimension the array automatically by assigning the range. If you need the numeric boundaries, use
nrows = UBound(oDebt, 1)
ncols = UBound(oDebt, 2)
Here you see the meaning of the dimension as well, index 1 is rows, index 2 is columns.