recordset.GetString in Access VBA Query returns an extra character after the result - sql

I have a query that I execute through VBA in Access 2010. The result of the query should be AFR, but it returns AFR with an extra line below it. I have added the "'" character to make the extra line visible.
TempHold = rs.GetString
Debug.Print "'" & TempHold & "'"
Returns this:
'AFR
'
But should return this:
'AFR'
I have tried using the below code, but none of the If statements evaluate as True. The code should check for a " ", a vbNewLine, or vbCrLf character but none evaluate as true. Does anyone know of any additional characters that would result in a new line?
If Right(TempHold, 1) = " " Then
TempHold = Left(TempHold, Len(TempHold) - 1)
ElseIf Right(TempHold, 2) = vbNewLine Or Right(TempHold, 2) = vbCrLf Then
TempHold = Left(TempHold, Len(TempHold) - 2)
End If

Use:
Asc(Right(TempHold, 1))
to get the Ascii character code.
Once you've found the character code (which, as you wrote in your comment, was 13), you can use your code to remove it:
If Right(TempHold, 1) = Chr(13) Then
TempHold = Left(TempHold, Len(TempHold) - 1)
End If
In this case, you can also use vbCr, which is the same as Chr(13).

The best way to get rid of the carriage return in my opinion is to stop it being created in the first place. This method is a lot tidier than having to remove the last character.
In the .GetString method there is a parameter for RowDelimiter which by default is set to be a carriage return. However you can change this to be whatever you want including a zero length string as follows:
rs.GetString(, , , "")
If you run your debug again with this code:
rs.GetString(, , , "")
Debug.Print "'" & TempHold & "'"
You will get this result:
'AFR'
Remember if you want something different to be placed between rows then just change the zero length string to whatever you need.

Related

Access VBA DCount data type mismatch in criteria expression when data types are obviously the same (both Text)

I'm doing a simple DCount, just looking for how many people have signed up for the same date and time. At the moment I'm just using a single date and a single time to prove the process, then I'll have it loop through all possible dates and times.
Private Sub Get_Singles()
Dim TestDate As String
Dim TestTime As String
AloneCnt = 0
Dinc = 0
Tinc = 0
TestDate = vStartDate
TestTime = "0700"
If (DCount("[ID]", VigilTable, "[fldTime] = " & TestTime) = 1) Then
' "[fldDate] = " & TestDate) & " And
AloneCnt = AloneCnt + 1
End If
End Sub
It works fine for the date (I've moved it to a different line and commented it out so I can focus on the time.).
In the table, fldDate and fldTime are both set for text (shows up as Field Size
= 255 in the properties list) and, as you can see, TestDate and TestTime are both dimmed as String.
And it works if I change the DCount line to:
(DCount("[ID]", VigilTable, "[fldTime] = '0700'")
So where's the error?
Thanks.
The error is, that you must handle date and time as data type Date. So change the data type of the fields to DateTime and:
Dim TestDate As Date
Dim TestTime As Date
Dim AloneCnt As Long
TestDate = vStartDate
TestTime = TimeSerial(7, 0, 0)
If DCount("*", "VigilTable", "[fldTime] = #" & Format(TestTime, "hh\:nn\:ss") & "# And [fldDate] = #" & Format(TestDate, "yyyy\/mm\/dd") & "#") = 1 Then
AloneCnt = AloneCnt + 1
End If
Because you hold all date/time bits as text/string, you should use the text syntax in the criteria as you showed: with quotes (notice the quotes around time string):
(DCount("[ID]", VigilTable, "[fldTime] = '" & TestTime & "'")
You could also keep Date/times in date types like #Gustav's answer.
Update:
You must be doing something wrong; here is my suggested version in VBA window, and it is not Red.
OK, I found the fix after searching several other sites; it was, as I suggested above, a problem of handling variables:
If (DCount("[ID]", VigilTable, "[fldDate]='" & TestDate & "'" & " AND [fldTime] = '" & TestTime & "'") = 1) Then
I always have trouble with those damned single quotes and can never get them in the right place (I'd tried placing single quotes several times but never got them where they are here.); I don't know if the rules are different in different places or I just don't understand the rules or both.
Thanks for all your suggestions; even things that don't work help.

Adding Logic for an Optional Argument in a Custom HL7 Parsing Function

I wrote a custom function that parses an HL7 interface message. These are messages sent between healthcare information systems, but basically it's just a long text string, delimited with various characters to indicate different fields, that I paste into a cell in Excel. The function I created searches and counts to find the fields specified in the arguments.
DISCLAIMER: I am new to VBA. I've been teaching myself via online research and trial-and-error over the past 3-4 weeks, so I'm no VBA expert. I'd prefer NOT to use arrays because when I tried that, the code got too complex for me to troubleshoot. So, I'm OK with the code being easy-to-follow, as opposed to being the fastest/most-efficient.
Anyhow, I've got it working pretty well to do what I want, but I'm stuck on adding in logic for an OPTIONAL argument.
So, this is how I WANT it to work:
Formula =KWHL7(A1, "MSH", 8)
NOTE only 3 arguments
Result I Want ADT^A08
Result I Get ADT
NOTE I know I told it to stop at the next instance of "HL7_SUBFIELD_DELIMITER" which is " ^ "
Formula =KWHL7(A1, "MSH", 8,1)
NOTE the optional 4th argument
Result I Want ADT
Formula =KWHL7(A1, "MSH", 8,2)
NOTE the optional 4th argument
Result I Want A08
The contents "value" of cell A1:
<11>MSH|^~\&|OPS|384|RISIC|384|20160923093012||ADT^A08|Q1230569238T1410271390|P|2.3|||*PM_ALLERGY*|||8859/1<13>
EVN||20160923<13>
PID|1||000000808^^^SCH MRN^MRN^SC||ZZTEST^LEANN||20160706|F|||459 CORPORATION ST.^^BEAVER^PA^15009^USA||(724)775-7418^PRN|||S||000000008082^^^SCH Account Number^FIN NBR|||||||0<13>
PV1|1|I|SCH Periop^^^^^^||||08888^Bullian^Leann~08888^Naylor^Daniel|||10|||||||08888^Nguyen-potter^Rose~00187^TEST^STCHRISRES^L^MD^^MD^^SCH Doc Number|1|1287593^^^TEMP FIN^VISITID||||||||||||||||||||384||A|||20160707131900<13>
PV2|||PA^<13>
OBX|1||Dosing Weight^WEIGHT||5|kg<13>
OBX|2||Height^HEIGHT||25|cm<13>
AL1|1|Drug|d00308^morphine^Multum Drug||66382015<13>
ZAL|||16655315|16655315||Active|66382015^Anaphylaxis^673967||||20160923093008|^Naylor^Daniel|0<13>
AL1|3|Drug|d00012^codeine^Multum Drug||103576018<13>
ZAL|||16655323|16655307||Active|103576018^Diarrhea^673967||||20160923093008|^Naylor^Daniel|0<13>
<28><13>
My VBA code (sorry for all the comments, I'm just learning!):
Public Function KWHL7(KW_Cell_With_HL7_Message As Variant, KW_HL7_Segment_Name As String, KW_HL7_Field_Number As Integer)
'KW_Cell_With_HL7_Message = KW_Cell_With_HL7_Message.Value
'KW_Cell_With_HL7_Message = ActiveCell.Value
'KW_HL7_Segment_Name = "PID"
'KW_HL7_Field_Number = 18
Const HL7_SEGMENT_DELIMITER = vbLf 'using "<13>" did not work due to carriage return
Const HL7_FIELD_DELIMITER = "|" ' Pipe means next field
Const HL7_SUBFIELD_DELIMITER = "^"
'Various carriage returns and line breaks: vbLf, vbCr, vbCrLf, vbNewLine, Chr(10), Chr(13)
KWSegmentStringToSearchFor = HL7_SEGMENT_DELIMITER & KW_HL7_Segment_Name 'Using the segment delimiter ("<13>" or "vbLf" / carriage return) before segment name implies that the segment / line STARTS with this text
KWSegmentCharacterPosition = InStr(1, KW_Cell_With_HL7_Message, KWSegmentStringToSearchFor)
'** FOR TESTING ** MsgBox ("Segment Character Position: " & KWSegmentCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWSegmentCharacterPosition, 5))
'Now we have the character position of the start of the proper SEGMENT / line
'Now we have to find the Proper Field in that segment
'So we'll use this position + the length of the end of the Segment Delimiter as the start
'***WARNING***: Still must add logic to make sure we stop if we encounter another Segment Delimiter
KWFieldCharacterPosition = KWSegmentCharacterPosition + Len(HL7_SEGMENT_DELIMITER) 'instead of starting at character 0, start at the beginning of the segment found previously
' ** FOR TESTING ** MsgBox ("Length of Segment Delimiter = " & Len(HL7_SEGMENT_DELIMITER))
' ** FOR TESTING ** MsgBox ("Field Character Position: " & KWFieldCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWFieldCharacterPosition, 5))
For J = 1 To KW_HL7_Field_Number
KWFieldCharacterPosition = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_FIELD_DELIMITER)
If KWFieldCharacterPosition = 0 Then Exit For
Next
' ** FOR TESTING ** MsgBox ("Field Character Position: " & KWFieldCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWFieldCharacterPosition, 5))
'Determine the number of characters to return after the start position
'Want to pull text UNTIL the next Segment Delimiter or Field Delimiter or Subfield Delimiter
'Find the position of the next Segment Delimiter or Field Delimiter or Subfield Delimiter
'Since the InStr function does not accept multiple substrings to search for, and does not allow OR statements inside...
Next_HL7_Segment_Delimiter = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_SEGMENT_DELIMITER)
Next_HL7_Field_Delimiter = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_FIELD_DELIMITER)
Next_HL7_Subfield_Delimiter = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_SUBFIELD_DELIMITER)
'Added logic to handle issue where the next delimiter was not found, making result 0, making it the lowest value in the next lines of code
If Next_HL7_Segment_Delimiter = 0 Then Next_HL7_Segment_Delimiter = 99999
If Next_HL7_Field_Delimiter = 0 Then Next_HL7_Field_Delimiter = 99999
If Next_HL7_Subfield_Delimiter = 0 Then Next_HL7_Subfield_Delimiter = 99999
'Set the Last Character Position to whichever Next Delimiter is the lowest / minimum number - Segment or Field or Subfield
KWLastCharacterPosition = WorksheetFunction.Min(Next_HL7_Segment_Delimiter, Next_HL7_Field_Delimiter, Next_HL7_Subfield_Delimiter)
' ** FOR TESTING ** MsgBox ("Last Character Position: " & KWLastCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWLastCharacterPosition, 5))
'Determine the number of characters to return in the MID function by subtracting the first character position from the last character position
KWNumberOfCharactersToReturn = KWLastCharacterPosition - KWFieldCharacterPosition - 1
' ** FOR TESTING ** MsgBox ("Number of characters to return: " & KWNumberOfCharactersToReturn)
KWResult = Mid(KW_Cell_With_HL7_Message, KWFieldCharacterPosition + 1, KWNumberOfCharactersToReturn)
'MsgBox ("Result: Segment " & KW_HL7_Segment_Name & ":" & KW_HL7_Field_Number & " is " & KWResult)
KWHL7 = KWResult
End Function
The problem I had with using the split function was that it put everything into arrays. And since I needed to search FIRST for the KWSegmentStringToSearchFor (i.e. "MSH" or "PV1"), before couting the pipe (|) characters, I would need the array to have separate nested arrays and it got way too confusing for me.
So I abandoned the split function, and my initial plans to use arrays, and just wrote everything to find things sequentially. So it searches for the KWSegmentStringToSearchFor (i.e. "MSH" or "PV1") with InStr() and then counts the pipe (|) characters from there to determine which number field to return.
Since the strings are of variable length, but delimited with special characters, next I have to determine how many characters to return with the MID function. So I search for the next delimiter FROM THERE / using the field I found as the starting point and call that the end of my field.
The issue:
The logic considers ANY of the 3 possible delimiters the end of the field.
If I take that out, the code wouldn't know where the end of the string is.
Even if I add some sort of IF statement that IF the optional 4th argument exists (which I'm not sure how to do yet), THEN ignore the ^ as a delimiter... that would always return the full field (ADT^A08). It wouldn't return just the sub-field / component I want.
Thanks!
A simple answer, would be to split on the LineFeed then it may need tweaking would be, split(range("a1").value,"|")(intFieldNumber)
i.e.
split("11>MSH|^~\&|OPS|384|RISIC|384|20160923093012||ADT^A08|Q1230569238T1410271390","|")(8)
gives the result ADT^A08

VBA function to convert name format

I want to take a name in First Last format and change it to Last, First. I know I could to this with a formula but I want to be complicated.
Please let me know if you see any red flags in my code, or suggestions for improvements.
Function LastFirst(Name_FL As String)
'This only works if there is a single space in the cell - Will Error If Spaces <> 1
Length = Len(Name_FL) 'Establishes Length of String
Spaces = Length - Len(Application.WorksheetFunction.Substitute(Name_FL, " ", "")) 'Number of spaces
If Spaces <> 1 Then
LastFirst = "#SPACES!#" 'Error Message
Else
SpaceLocation = Application.WorksheetFunction.Find(" ", Name_FL, 1) 'Location of space
Last = Right(Name_FL, Length - SpaceLocation) 'Establishes Last Name String
First = Left(Name_FL, SpaceLocation) 'Establishes First Name String
LastFirst = Application.WorksheetFunction.Proper(Last & ", " & First) 'Puts it together
End If
End Function 'Ta-da
You could simplify it to:
Function LastFirst(Name_FL As String) As String
If (Len(Name_FL) - Len(Replace(Name_FL, " ", ""))) > 1 Then
LastFirst = "#SPACES#"
Else
LastFirst = StrConv(Split(Name_FL, " ")(1) & ", " & Split(Name_FL, " ")(0), vbProperCase)
End If
End Function
The logic here is:
If there is more than 1 space, return the error string #SPACES#
If there is 1 space, the split the string using " " as a delimiter.
Use the second index of the Split array, add ", " and use the first index of the split array.
Use StrConv() to convert it all to proper case.
You might also want to add another check for no spaces:
If InStr(Name_FL, " ") > 0 Then
'// There is a space in the string
Else
'// There is no space in the string
End If
Which can also be tested for by slightly changing the logic of the above example:
Function LastFirst(Name_FL As String) As String
If (Len(Name_FL) - Len(Replace(Name_FL, " ", ""))) = 1 Then
LastFirst = StrConv(Split(Name_FL, " ")(1) & ", " & Split(Name_FL, " ")(0), vbProperCase)
Else
LastFirst = "#SPACES#"
End If
End Function
Further elaboration on functions:
You can see I've used some VBA functions here in place of your WorksheetFunction methods.
Len() returns the Length of a string.
Replace() does what it says on the tin - replaces a given string with another.
StrConv() Converts a String to a respective case (e.g. vbProperCase).
Split() Creates a zero-based single dimension array from a string, by Splitting it on a given delimiter.
Finally - Don't forget to specify a return value in your function header:
Function LastFirst(Name_FL As String)As String<~~ return type

What does "& _" mean in VB?

I'm copying some query statements from a legacy VB app to a C# app. I am not familiar with VB, although looking at it makes me want a VB (Victoria Bitter). I have come across queries constructed like this:
*SELECT dp_duckbill_accounts.platypus_no AS duckbill, t_accounts.name AS Name " & _
"FROM t_accounts INNER JOIN dp_duckbill_accounts ON t_accounts.account_no = dp_duckbill_accounts.account_no " & _
"ORDER BY dp_duckbill_accounts.platypus_no*
The "& _" give me pause. If it was just "&" I would think it corresponds to "+" in C# to concatenate strings. But what in the world is the point of the underscore? Note the ampersand and the underscore are separated by a space.
The underscore is the line continuation character. It allows the concatenation to include a different line. Like so:
x = "Hello " & "World"
x = "Hello " & _
"World"
'this won't compile (pre vb.net 2010, anyway)
x = "Hello " &
"World"
Line Continuation on MSDN
How to: Break and Combine Statements in Code (Visual Basic)
_ means continue the statement on the following line.
so ... & _ means continue concatenating the string on the following line.
text = "One line string"
text = "Two line " & _
"string"
That is just a line continuation character that lets you continue to the next line.
& - is used for string concatenation in same line.
example - sConcatenatedString = "First" & "Second"
& _ - is used For string concatenation in different lines.
example - sConcatenatedString = "First" &_
"Second"

Sql queries in VBA code - how to comment after Sql string

I have some Sql queries inside VBA code, this is an example of a line of code:
strQry = strQry & Worksheets("Data").Cells(9, 7) & """, " & _
I need to add a comment at the end of this line. Like this:
strQry = strQry & Worksheets("Data").Cells(9, 7) & """, " & _ 'comment hjjkk
I usually comment using an apostrophe but the character is not accepted on that line. Please advise. Also, I need the comment on that exact line if possible, at the end of it.
Thank you!
This has nothing to do with the SQL query itself, you are trying to add a comment after a line continuation, which is not allowed.
From the MSDN documentation on comments:
Comments cannot follow a line-continuation sequence on the same line.
If you do & _ it means you got code on the next line and that instruction is not finished.
So if you type a comment right after & _ it's like if your inserting a comment in the middle of your instruction
For example:
myVar = 3 + 5 & _ 'comment at the wrong place
+2
=
myVar = 3 +5 'comment at the wrong place + 2
So all you can do is
myVar = 3 + 5 'comment
myVar = myvar + 2
or in your case it would look like this
strQry = strQry & Worksheets("Data").Cells(9, 7) & """, " 'Comment
strQry = styQry &...
with the line break _ you cannot comment on that line as for VB the line doesn't stop yet (it is a feature to improve readability for us programmers). Get accustomed to comment before or after the complete string
Alternatively you can build the string up in parts and after each part you can add comments:
strQry = strQry & Worksheets("Data").Cells(9, 7) 'comment 1
strQry = strQry & ", " & <next part> 'comment2
etc...
The underscore at the end of the line signifies to VB that the code continues on the next line. You can't put anything after the underscore. If you need a comment at the end of the line, you will need to restructure your code to end that line, put your comment and continue your string concatenation on the next line.