Concatenate Multiple Strings While Ignoring Null Values - ms-access

I'm trying to figure out a solution on how to concatenate strings from about 15 different options. Each result comes from a checkbox that is selected based on the state a person has lived in within a certain area.
I know how to turn the checkbox option into a text result. What I'm looking for is how to take these text results, combine them, then ignore null results so there isn't any weird spacing or formatting.
In short, if someone select 3 of the 15 results it would combine the 3 results cleanly and ignore the rest. Example would be: FL, CA, NY

There are, of course, multiple ways that this can be achieved, and since you didn't provide any code or examples of how you are attempting to do this, I will provide two options.
1 - You can concatenate the values using a combination of the & and + operators.
For example, let's say you have 15 checkboxes, all named similarly like chkState01, chkState02 ... through chkState15. And for the simplicity of my sample code, let's assume that when referencing the checkbox control directly in code as chkState01 that it will return either the 2 letter string abbreviation of the State it represents (i.e. NY) if the checkbox was checked, or it will return Null if the checkbox was not checked. With that, you could get your results in 2 ways:
Option A
StateList = (chkState01 + ",") & (chkState02 + ",") & (chkState03 + ",") ....
If those 3 check boxes returned the following values
chkState01 = "NY"
chkState02 = Null
chkState03 = "FL"
Then the result of that concatenation code would be:
NY,FL,
Notice that the string ends with an extra comma (,) and always would since you can't know ahead of time how many of the checkboxes will be checked. You would then need to trim that comma from your list before using it most likely.
Option B
'Create the list with a trailing comma that will need removed
Dim x as Integer
For x = 1 to 15
StateList = StateList & (Me("chkState" & Format(x, "00")) + ",")
Next x
or, you could do:
'Create the list without a trailing comma
Dim x as Integer
For x = 1 to 15
If Not IsNull(Me("chkState" & Format(x, "00"))) Then
If Len(StateList) > 0 Then
StateList = StateList & "," & Me("chkState" & Format(x, "00"))
Else
StateList = Me("chkState" & Format(x, "00"))
End If
End If
Next x
Notice that you can reference a control on a form by "generating" the name of that control as a string and referencing it in the Me("yourcontrolname") format. This is one advantage to naming controls that are similar in a fashion that lends itself to a looping structure like this. The Format command formats the number returned by x as a 2 digit with leading zeros i.e. 1 becomes 01
Further, using & to concatenate two items, where at least one of them is a string, will always result in a string output (Null & "S" = "S"). However, using the + to concatenate two items, where at least one of them is a Null, will always result in Null output (Null + "S" = Null). Hence the checkboxes where the value returns Null does not cause additional commas to be included in the result.
2 - You can write more complicated code to dynamically loop through the checkboxes and build the output list.
More likely, you are going to need to use additional code to determine which checkbox is which state abbreviation and to return the correct string value. Maybe you made the state abbreviation part of the checkbox name i.e. chkState_NY, chkState_FL or maybe you have put the abbreviation in the Tag property of each checkbox.
Let's say you used special control naming chkState_NY, chkState_FL. You could do the following:
Dim ctl as Access.Control
For Each ctl in Me.Controls
If ctl.Name Like "chkState_??" Then
If ctl.Value = True Then
If Len(StateList) > 0 Then
StateList = StateList & "," & Right(ctl.Name,2)
Else
StateList = Right(ctl.Name,2)
End If
End If
End If
Next ctl

Related

Find the position of the first occurrence of any number in string (if present) in MS Access

In MS Access I have a table with a Short Text field named txtPMTaskDesc in which some records contains numbers, and if they do, at different positions in the string. I would like to recover these numbers from the text string if possible for sorting purposes.
There are over 26000 records in the table, so I would rather handle it in a query over using VBA loops etc.
Sample Data
While the end goal is to recover the whole number, I was going to start with just identifying the position of the first numerical value in the string. I have tried a few things to no avail like:
InStr(1,[txtPMTaskDesc],"*[0-9]*")
Once I get that, I was going to use it as a part of a Mid() function to pull out it and the character next to it like below. (its a bit dodgy, but there is never more than a two-digit number in the text string)
IIf(InStr(1,[txtPMTaskDesc],"*[0-9]*")>0,Mid([txtPMTaskDesc],InStr(1,[txtPMTaskDesc],"*[0-9]*"),2)*1,0)
Any assistance appreciated.
If data is truly representative and number always preceded by "- No ", then expression in query can be like:
Val(Mid(txtPMTaskDesc, InStr(txtPMTaskDesc, "- No ") + 5))
If there is no match, a 0 will return, however, if field is null, the expression will error.
If string does not have consistent pattern (numbers always in same position or preceded by some distinct character combination that can be used to locate position), don't think can get what you want without VBA. Either loop through string or explore Regular Expressions aka RegEx. Set reference to Microsoft VBScript Regular Expressions x.x library.
Function GetNum(strS AS String)
Dim re As RegExp, Match As Object
Set re = New RegExp
re.Pattern = "[\d+]+"
Set Match = re.Execute(strS)
GetNum = Null
If Match.Count > 0 Then GetNum = Match(0)
End Function
Input of string "Fuel Injector - No 1 - R&I" returns 1.
Place function in a general module and call it from query.
SELECT table.*, GetNum(Nz(txtPMTaskDesc,"")) AS Num FROM table;
Function returns Null if there is no number match.
Well, does the number you want ALWAYS have a - No xxxx - format?
If yes, then you could have this global function in VBA like this:
Public Function GNUM(v As Variant) As Long
If IsNull(v) Then
GNUM = 0
Exit Function
End If
Dim vBuf As Variant
vBuf = Split(v, " - No ")
Dim strRes As String
If UBound(vBuf) > 0 Then
strRes = Split(vBuf(1), "-")(0)
GNUM = Trim(strRes)
Else
GNUM = 0
End If
End Function
Then your sql will be like this:
SELECT BLA, BLA, txtPMTaskDesc, GNUM([txtPMTaskDesc] AS TaskNum
FROM myTable
So you can create/have a public VBA function, and it can be used in the sql query.
It just a question if " - No -" is ALWAYS that format, then THEN the number follows this
So we have "space" "-" "space" "No" "space" "-" -- then the number and the " -"
How well this will work depends on how consistent this text is.

Access will only retrieve data from 1 table in a join with no where clause

I am using MS-Access to get information from 2 tables. I have used inner join, left, right, and outer with all variations, and it will either pull 1 row when 316 are expected, all data for the fields in test with no values for the fields from test 1, or all data for fields from test 1, and no values for test. How do I resolve this? The actual fields had to be changed for privacy, but the below is the exact layout.
SELECT [TEST].a,
[TEST].b,
[TEST].c,
[TEST 1].[D],
[TEST].E,
[TEST].F,
[TEST].G,
[TEST].H,
[TEST 1].[I],
[TEST].J,
[TEST].K,
[TEST 1].L,
[TEST 1].[M]
FROM [TEST 1]
INNER JOIN [TEST] ON [TEST 1].[ID] = [TEST].[CLAIMSNO];
This is a data-validation and debugging exercise, so if you can't share concrete example data then there is really no definite answer to this question. Technically it may not be answerable according to common StackOverflow standards, but I feel generous right now.
Since the joined fields are text, there are various possibilities keeping them from matching: extra spaces, null-terminated strings, case sensitivity (although Access by default should be case insensitive), wide (Unicode) vs narrow (ASCII, UTF-8) encoding, etc. You did not reveal where the data came from, nor how it was loaded into the database, so I make no assumptions. In order to understand the data and determine the reason for the failed matches, you need to investigate the details of the strings. You could likely narrow the problem by investigating the source of the data values and understanding the range of possible characters, encoding, string termination, etc.
Since you are already having troubles matching data AND since you already indicated that the original tables had no primary key or indexes, I highly recommend adding a new AutoNumber field with a unique index to each table, perhaps named [AID] (for AutoNumber ID). Do this even if you have added indices to existing columns. This will at least provide a reliable "handle" to select and refer to a particular row while debugging the other columns.
The big idea is to use VBA or other built-in functions to inspect and report on various attributes of the string values. There are just too many ways you could do this, but my preference is to create a public VBA function in a normal VBA module and then call this function from an SQL query. Although you could do this for every row, instead I suggest manually choosing rows from each table which you think should match... record the [AID] value for each row. If the manually-selected rows don't result in anything enlightening, then run it against an entire table and see what interesting results you get.
Consider these functions:
Public Function CheckSpaces(val As Variant) As String
Dim result As String
If IsNull(val) Then
result = "Null"
ElseIf VarType(val) = VbVarType.vbString Then
If Len(val) = 0 Then
result = "Empty String"
Else
Dim temp As String
Dim n As Integer, m As Integer
n = Len(val)
result = "Length " & n
temp = LTrim(val)
m = Len(temp)
If n <> m Then
result = result & " AND " & (n - m) & " left spaces"
End If
temp = RTrim(val)
m = Len(temp)
If n <> m Then
result = result & " AND " & (n - m) & " right spaces"
End If
End If
Else
result = "Not a string!"
End If
CheckSpaces = result
End Function
Public Function NullChar(val As Variant) As Boolean
Dim result As Boolean
result = False
If Not IsNull(val) Then
If VarType(val) = VbVarType.vbString Then
If InStr(val, vbNullChar) > 0 Then 'vbNullChar = Chr(0)
result = True
End If
End If
End If
NullChar = result
End Function
And execute queries similar to the following. Let's say that [Test 1] row AID = 10 has [ID] == 'name'. Likewise, imagine row AID == 20 of [Test] has [CLAIMSNO] = ' name ':
SELECT [ID], CheckSpaces([ID]), NullChar([ID])
FROM [TEST 1]
WHERE [AID] = 10
and
SELECT [CLAIMSNO], CheckSpaces([CLAIMSNO]), NullChar([CLAIMSNO])
FROM [TEST]
WHERE [AID] = 20
Compare the returned values. Is there anything that indicates a failed match?

How to display number values with commas in form

In my Access query, I have the query using a VBA function to figure the value that goes in the query field.
In the form, if the stringval textbox has a value, then I want to compute it, but if not, it should remain empty (null).
Function GetValue(stringval, numval)
Dim result
stringval= stringval & ""
result= IIf(stringval<> "", numval* 1.5, Null)
GetValue = Int(result)
End Function
Now, I have a form that uses this query, and on the form is a textbox that displays the query value. I want the value to be formatted with commas in the numbers for easy reading. Everything I've tried so far does not show any commas.
I've tried:
used Standard for the Format > Formatfor the textbox (in properties)
putting #,###.### in the textbox Format value
putting #,##0.0## in the textbox Format value
changing Data > Text Format but it only gives me Plain Text and Rich Text - no option for numbers.
returning a double from the function
Note: if I don't use a custom VBA function, and write the formula directly into the query, then it does display commas. But when I move the formula into the function then the commas are lost.
What do I do?
[update]
I tried Gustav's solutions and since they didn't work for me, I added those as items to my "what I've tried" list above.
Also, if I look at the query in datasheet view, the number values sort alphabetically instead of by the size of the value. When I used the forumulae directly in the query instead of using functions, it sorted by the value of the number. I hope this is a clue.
Numbers carries no format. A format is applied when displayed only.
But be sure to return a Double if not Null:
Function GetValue(stringval, numval)
Dim result
If stringval & "" <> "" Then
result = Int(CDbl(numval) * 1.5)
Else
result = Null
End If
GetValue = result
End Function
Then apply your Format to the textbox
#,##0.0##
Or force a formatted string to be returned:
If stringval & "" <> "" Then
result = Format(Int(CDbl(numval) * 1.5), "#,##0.0##")
Else
result = Null
End If
and skip formatting of the textbox.
The solution is this: the function has to be declared as a double.
That allows the query's datasheet view to know it is displaying numbers - and so you can set the field's format to Standard for the comma to display. This also allows the form to know it has a number and it will display the comma there, too. I knew it had to do with double, but didn't realize before that the function needed to be declared as such.
Function GetValue(stringval, numval) as double '<----THIS!!!!
Dim result
If stringval & "" <> "" Then
result = numval * 1.5
Else
result = 0 `<--can't return null here; use nz function in control source for textbox
End If
GetValue = int(result) 'to remove decimals
End Function
The problem I was having was in some of my functions I need to return double or null, because I wanted textboxes to remain blank if they contained no data. Now, at least I know how to make the numbers generated by functions to display commas.
And here is how to deal with the fact that you can't return null as the value of a double. The function is originally from here.
Put this function in a module so it is public, and then in the control source for the textbox, instead of just putting the field value, put Zn(fieldvalue). This works like a charm (although using functions in the control source seems to have a delay on the form display). This way you can keep the underlying value as a double and still get commas to display in both the form and the query whilst keeping the field blank if necessary.
Public Function Zn(pvar)
' Return null if input is zero or ""
If IsNull(pvar) Then
Zn = Null
ElseIf IsNumeric(pvar) Then
If pvar = 0 Then
Zn = Null
Else
Zn = pvar
End If
Else
If Len(pvar) = 0 Then
Zn = Null
Else
Zn = pvar
End If
End If
End Function

formatting phone numbers ms access

Sorry, another question about MsAccess.
I have data set:
Phone Number
444-514-9864
555-722-2273
333-553- 4535
000-000- 0000
550-322-6888
444-896-5371
322-533-1448
222.449.2931
222.314.5208
222.745.6001
I need it to look like (222) 896-5371.
How do I do it in Ms Access or MsExcel?
You can use the Instr, mid, Left and Right functions to make this work. I have made 1 example, with msdn you should be able to figure out the rest
Dim OldPhoneNumber As String
Dim NewPhoneNumber As String
Dim PreFix As String
Dim PreFix2 As String
' You can replace this line in Access, just make sure the full phone number is stored in "OldPhoneNumber"
OldPhoneNumber = Worksheets(<worksheet name>).Range(<cell name>).Value
PreFix = Left(OldPhoneNumber, InStr(1, OldPhoneNumber, "-", 1))
PreFix2 = Left(OldPhoneNumber, InStr(1, OldPhoneNumber, "-", 1) - 1)
NewPhoneNumber = Replace(OldPhoneNumber, PreFix, "(" & PreFix2 & ") ")
Debug.Print (NewPhoneNumber)
Seeing as not all your phone numbers are formatted the same way, you would have to make a different rule for every different formatted phone number (you need 1 that checks for "-" and one that checks for "." You also might want to filter out the spaces
In Access you set the "Input mask" to : "("000") "000"-"0000;1;_
All the references http://office.microsoft.com/en-ca/access-help/input-mask-syntax-and-examples-HP005187550.aspx
Input mask will only work for new data. You will need to create a macro or function to update your existing data to be consistent with your desired format

How can you check for null in a VBA DAO record set?

I have an optional field in a database that I'm pulling out using a DAO Record Set. I need to check whether or not the field is set before I concatenate it with other fields. So far I have the following code snippet which I've tried with both Is and = (that's the obviously wrong syntax [[Is | =]]) to no avail. It appears that if I use = it will not correctly compare with Null and if I use Is then it complains that it's not comparing with an Object.
While Not rs.EOF
If rs.Fields("MiddleInitial") [[Is | =]] Null Then thisMiddleInitial = "" Else thisMiddleInitial = rs.Fields("MiddleInitial")
If prettyName(myLastName, myFirstName, myMiddleInitial) = prettyName(rs.Fields("LastName"), rs.Fields("FirstName"), thisMiddleInitial) Then
MsgBox "Yay!"
End If
rs.MoveNext
Wend
If there's a simpler way to do this I'm totally open to it. prettyName takes 3 Strings as parameters and initially I was just trying to pass rs.Fields("MiddleName") directly but it threw up at a Null value. I'd prefer to do something more direct like that but this is the best I could come up with.
How about:
IsNull(rs.Fields("MiddleInitial").Value)
You could also have a look at this article which has some explanation about Null values in Access VBA apps and how to handle them.
For the example you show, Nz would work:
thisMiddleInitial = Nz(rs!MiddleInitial,"")
Or simply concatenating the string with an empty string:
thisMiddleInitial = rs!MiddleInitial & ""
Your question has been answered by Remou, seems to me, but it occurs to me that you may just be trying to get proper concatenation of the name fields. In that case, you could use Mid() and Null propagation in VBA to get the result.
I don't use separate middle initial fields, so my usual name concatenation formula is:
Mid(("12" + LastName) & (", " + FirstName), 3)
The "12" string at the beginning is going to be tossed away if LastName is Not Null and ignored if it is null, because the + concatenation operator propagates Nulls.
To extend this to include middle intials would look like this:
Mid(("12" + LastName) & (", " + FirstName) & (" " + MiddleInitial), 3)
Assuming your UDF is not doing some kind of complicated cleanup of nicknames/abbreviations/etc., this could replace it entirely, seems to me.
If rst.Fields("MiddleInitial").Value = "Null" Then
This works for me. I use MS SQL Database.
I think the NoMatch option might work in this situation:
If rs.NoMatch = True Then
I prefer using the below to account for both Null and Empty string values. It's a good check to use you have forms collecting values from users.
If Trim(rs.Fields("MiddleInitial") & "") = "" then