I have a GPS truck tracking DB i am working with and I want to remove all the Letters from a certain column. Or if it is easier extrapolate all the Numbers and put them in their own column. The Left, Right, Mid will not work because the numeric value for each number position changes line to line.Screen Shot of DB
I am not sure this is even possible in access or if I will have to pass the data through python to do what I am wanting.
try
InStr( startPosition, "abcdefg", "c" )
returns the character position of "c" in "abcdefg", 0 if no match.
Either use vba to programmatically process the records or use queries directly but not as efficient.
ex. (step by step to make it clearer)
SELECT IIf( InStr(1,[description],"odo:")>0, "found", "not found" )
AS Result FROM MyTable;
replace "found" with:
Mid( [description], InStr(1,[description],"odo:")+3 )
this will chop off everything on the left "On Duty, odo:", "Driving, odo:".
Since it is not posible to store into temporary variables in queries, just use up several InStr() to find "odo:" and possibly " Miles" then use them again to compute the length. For small number of records this will be fine, otherwise better use VBA for efficiency.
The following are two methods to return only digits - but you need to tell us which field(s) you want to parse.
Option Compare Database
Option Explicit
Function Test_This()
Dim strIN As String
strIN = "On Duty, odo: 245678.9,"
MsgBox "Loop Method:" & vbCrLf & "Input String: " & strIN & vbCrLf & "Output String: " & Method_Loop(strIN)
MsgBox "Parse Method:" & vbCrLf & "Input String: " & strIN & vbCrLf & "Output String: " & Method_Parse(strIN)
End Function
Function Method_Parse(InValue As String) As String
Dim i As Integer
Dim i2 As Integer
Dim iLen As Integer
Dim strOut As String
iLen = Len(InValue)
i2 = 0
strOut = ""
' Assume delimiter is colon + space
i = InStr(1, InValue, ": ")
If i = 0 Then
MsgBox "No starting delimiter (: ) for '" & InValue & "'", vbOKOnly, "No Start Delimiter"
Method_Parse = ""
Exit Function
End If
i2 = InStr(i, InValue, ",")
If i2 = 0 Then
MsgBox "No ending delimiter (,) for '" & InValue & "'", vbOKOnly, "No End Delimiter"
Method_Parse = ""
Exit Function
End If
strOut = Mid(InValue, i + 2, i2 - i - 2)
Method_Parse = strOut
End Function
Function Method_Loop(InValue As String) As String
Dim i As Integer
Dim i2 As Integer
Dim iLen As Integer
Dim strOut As String
iLen = Len(InValue)
i2 = 0
strOut = ""
For i = 1 To iLen
' If you can have a period that is not part of the number,
' and your number's can have decimal places, then modify the code
' to check if 'IsNumeric' for the prefeeding and following characters.
If (IsNumeric(Mid(InValue, i, 1))) Or (Mid(InValue, i, 1) = ".") Then
strOut = strOut & Mid(InValue, i, 1)
End If
Next i
Method_Loop = strOut
End Function
Looks like from that screenshot you can use:
X = InStr(0, Description, ":" ) 'Gets the position of the first semicolon
Y = InStr(X, Description, "," ) 'Gets the position of the following comma
Then you can use those two numbers in a Mid statement:
Z = Mid(Description, X + 1, Z - 1)
That should give you the odometer reading.
If you need other numbers, just continue on with that logic.
Related
<!-- Function 1-->
Function GetStudentResultTotal(ByVal schid As String, ByVal level As String, ByVal session As String, ByVal term As String, ByVal klass As String, ByVal regno As String) As Double
If SCH_ID <> "" Then
schid = SCH_ID
End If
Dim total As Double = 0
Dim subjectCount As Integer = 0
Dim fields As New ArrayList
fields.Add("SUM(" & StudentData.Total & ") AS GrandTotal")
Dim filterValues As New Hashtable
filterValues.Add(StudentData.SchoolID, schid)
filterValues.Add(StudentData.Level, level)
filterValues.Add(StudentData.Session, session)
filterValues.Add(StudentData.Term, term)
filterValues.Add(StudentData.Klass, klass)
filterValues.Add(StudentData.RegNo, regno)
Dim filterArgs As String = "WHERE " & StudentData.SchoolID & "=#" & StudentData.SchoolID & " AND " & StudentData.Level & "=#" & StudentData.Level & " AND " & StudentData.Session & "=#" & StudentData.Session & " AND " & StudentData.Term & "=#" & StudentData.Term & " AND " & StudentData.Klass & "=#" & StudentData.Klass & " AND " & StudentData.RegNo & "=#" & StudentData.RegNo
Dim data As DataSet = _Data.GetData(StudentData.tblStudentResult, fields, filterValues, filterArgs)
'If data.Tables(0).Rows.Count > 0 Then
' For Each dr As DataRow In data.Tables(0).Rows
' total += CDbl(NormalizeRecord(dr(StudentData.Total)))
' subjectCount += 1
' Next
'End If
Dim dr As DataRow = data.Tables(0).Rows(0)
total = CDbl(dr("GrandTotal"))
Return total
End Function
<!-- Function 2-->
Function GetData(ByVal tbl As String, ByVal values As ArrayList, ByVal filters As Hashtable, ByVal filterArgs As String) As DataSet
Dim _ds As New DataSet
Dim sql As String = "SELECT "
Dim fields As String = ""
Using conn As New MySqlConnection(connString)
conn.Open()
If values IsNot Nothing Then
For i = 0 To values.Count - 1
If fields = "" Then
fields = values.Item(i).ToString
Else
fields &= "," & values.Item(i).ToString
End If
Next
sql &= fields & " "
End If
sql &= "FROM " & tbl
If filterArgs <> "" Then
sql &= " " & filterArgs
End If
Dim cmd As New MySqlCommand(sql, conn)
If filters IsNot Nothing Then
For i = 0 To filters.Count - 1
cmd.Parameters.AddWithValue("#" & filters.Keys(i), filters.Values(i))
Next
End If
Dim da As New MySqlDataAdapter(cmd)
da.Fill(_ds)
conn.Close()
End Using
Return _ds
End Function
<!-- Function 3-->
Function NormalizeRecord(ByVal value As String) As String
If value = "-" Then
value = "0"
End If
Return value
End Function
Function 1 as described in my code is supposed to sum the column total and return the result but it always throw error (Conversion from type dbnull to type double is not valid) if it returns null value especially when am inserting record for the first time. how can i control null value?
Well, there are two ways to deal with this.
First up, you might have no rows, or the ONLY row returned has a null value.
If you doing a "sum()", then if ANY of the rows are not null, then you WILL get a value back.
however, no rows, or rows with the column that are null, then you see/get/find a null.
So, one easy fix would be to use isnull.
So, your code could say use this:
.Add("IsNull(SUM(" & StudentData.Total & "),0) AS GrandTotal")
The above is probably your best bet, since EVEN if the query were to not even return any rows due to filter, you still get a 0 back.
Edit: I see you tagged this as MySQL, and not SQL server - my mistake, so I suggest using below solution.
however, often, in fact quite a bit, you will encounter null values in your data tables
(BTW, why are you using a dataset in place of a data table? You don't need a dataset here, since you don't have a colleciton of tables).
So, next up, since you often have do to this?
Place in your "system wide" bag of utility routines this:
Public Function Nz(ByVal Value As Object,
Optional ByVal MyDefault As Object = "") As Object
If Value Is Nothing OrElse IsDBNull(Value) Then
Return MyDefault
Else
Return Value
End If
End Function
So, now you can say do this:
total = nz(dr("GrandTotal"),0)
You could/can modify the SQL query, and have it return a 0 value for those null rows.
My String (strSQL) Value is 1,2,3,,4 and My result shows blank between 3 and 4 due to Double comma (,,). My Code is Following:-
strParts = Split(strSQL, ", ")
For intCounter = LBound(strParts()) To UBound(strParts())
Me.Controls("cmd" & intCounter).Visible = True
Me.Controls("cmd" & intCounter).Caption = strParts(intCounter)
Next intCounter
You can replace a double (,,) by a single one (,) before splitting:
strSQL = Replace(strSQL, ",,", ",")
Or you use a separate index:
strParts = Split(strSQL, ",")
Dim index As Long
Dim counter As Long
For index = LBound(strParts()) To UBound(strParts())
If Len(Trim(strParts(index))) > 1 Then
counter = counter + 1
Me.Controls("cmd" & counter).Visible = True
Me.Controls("cmd" & counter).Caption = strParts(index)
End If
Next index
As you also could have tripled commas, just ignore the empty entries:
Dim Part As String
strParts = Split(strSQL, ",")
For intCounter = LBound(strParts()) To UBound(strParts())
Part = Trim(strParts(intCounter))
If Part <> "" Then
Me.Controls("cmd" & Part).Visible = True
Me.Controls("cmd" & Part).Caption = Part
Else
Me.Controls("cmd" & Part).Visible = False
End If
Next
I think the best way to do this is to "sanitize" your string to remove extra commas before splitting. However, as #Gustaf notes, you could have more than 2 commas in a row. So a possible solution is to iteratively remove extra commas until you don't have any. Such a function looks like this:
' given a string that contains consecutive commas (e.g. abc,,def,,,ghi),
' removes all but the first commas (e.g. abc,def,ghi
Public Function RemoveDuplicateCommas(ByVal s As String) As String
Do While InStr(1, s, ",,", vbBinaryCompare) > 0
s = Replace(s, ",,", ",")
Loop
RemoveDuplicateCommas = s
End Function
To use this function, do something like this:
strSQL = "1,2,3,,4,,,5"
strSQL = RemoveDuplicateCommas(strSQL)
?strSQL
1,2,3,4,5
?join(split(strsql, ","), ",")
1,2,3,4,5
I am using this code to call a random alpha numeric string. I am doing so via textbox in an Access Form.
https://www.devhut.net/2010/06/22/ms-access-vba-generate-a-random-string/
I am trying to get it to also validate it's uniqueness in a column in Access. When it fails it should run again. It however fixes that problem by doubling the digits it generates. For example to test this I am running it on a field populated with entries from 01-98. It should generate only a two digit numeric string but it returns a 4 digit.
I'm no coder btw and very unfamiliar with VB. I just rip code off the internet, and pray it works. So I might not understand things when you reply back.
Function GenRandomStr(iNoChars As Integer, _
bNumeric As Boolean, _
bUpperAlpha As Boolean, _
bLowerAlpha As Boolean)
On Error GoTo Error_Handler
Dim AllowedChars() As Variant
Dim iNoAllowedChars As Long
Dim iEleCounter As Long
Dim i As Integer
Dim iRndChar As Integer
Dim varCountOfResults As Integer
varCountOfResults = 1
While varCountOfResults > 0
'Initialize our array, otherwise it throws an error
ReDim Preserve AllowedChars(0)
AllowedChars(0) = ""
'Build our list of acceptable characters to use to generate a string from
'Numeric -> 48-57
If bNumeric = True Then
For i = 48 To 57
iEleCounter = UBound(AllowedChars)
ReDim Preserve AllowedChars(iEleCounter + 1)
AllowedChars(iEleCounter + 1) = i
Next i
End If
'Uppercase alphabet -> 65-90
If bUpperAlpha = True Then
For i = 65 To 90
ReDim Preserve AllowedChars(UBound(AllowedChars) + 1)
iEleCounter = UBound(AllowedChars)
AllowedChars(iEleCounter) = i
Next i
End If
'Lowercase alphabet -> 97-122
If bLowerAlpha = True Then
For i = 97 To 122
ReDim Preserve AllowedChars(UBound(AllowedChars) + 1)
iEleCounter = UBound(AllowedChars)
AllowedChars(iEleCounter) = i
Next i
End If
'Build the random string
iNoAllowedChars = UBound(AllowedChars)
For i = 1 To iNoChars
Randomize
iRndChar = Int((iNoAllowedChars * rnd) + 1)
GenRandomStr = GenRandomStr & Chr(AllowedChars(iRndChar))
Next i
varCountOfResults = DCount("userentry", "tamontupd", "userentry = '" & GenRandomStr & "'")
Wend
Error_Handler_Exit:
On Error Resume Next
Exit Function
Error_Handler:
MsgBox "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: GenRandomStr" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
You need to add GenRandomStr = "" at the top of the loop, otherwise a second/third trip through will just add to the existing string.
Refactored a little and untested because I don't have Access:
Function GenRandomStr(iNoChars As Integer, _
bNumeric As Boolean, _
bUpperAlpha As Boolean, _
bLowerAlpha As Boolean)
Dim AllowedChars As String, iEleCounter As Long
Dim i As Long, iRndChar As Long, iNoAllowedChars As Long
If bNumeric Then AllowedChars = "0123456789"
If bUpperAlpha Then AllowedChars = AllowedChars & "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If bLowerAlpha Then AllowedChars = AllowedChars & "abcdefghijklmnopqrstuvwxyz"
iNoAllowedChars = Len(AllowedChars)
Do
GenRandomStr = ""
For i = 1 To iNoChars
Randomize
iRndChar = Int((iNoAllowedChars * Rnd) + 1)
GenRandomStr = GenRandomStr & Mid(AllowedChars, iRndChar, 1)
Next i
Exit Do
Loop While DCount("userentry", "tamontupd", "userentry = '" & GenRandomStr & "'") > 0
End Function
New to MS Access and was curious if there is a way to tell if a barcode that is scanned is either a FedEx barcode or a UPS barcode. From what I've seen, UPS has alpha numeric barcodes and FedEx has 12 digit numeric barcodes. I'm sure this varies.
I would like to add another column to the table called "Type_TrackNum" that will store whether the label is FedEx or UPS. I would like for this to be attached to the CurrentDB.Execute command.
Here is what I have so far, this also cuts off the leading zeros whenever there are leading zeros, typically found in FedEx barcodes.
Dim strIn As String
Dim i As Integer
Dim iLen As Integer
strIn = Me.txt_Track.Value
iLen = Len(strIn)
For i = 1 To iLen
If InStr(strIn, "0") = 1 Then
strIn = Mid(strIn, 2)
End If
Next i
CurrentDb.Execute _
"INSERT INTO TrackNum_Table(TrackingNum_TrackNum) " & _
"VALUES ('" & strIn & "')"
Any assistance would be helpful.
Something like
Dim strIn As String
Dim strType As String 'NEW
Dim i As Integer
Dim iLen As Integer
strIn = Me.txt_Track.Value
iLen = Len(strIn)
If IsNumeric(strIn) Then
strType = "FedEx"
For i = 1 To iLen
If Left(strIn, 1) = "0" Then
strIn = Mid(strIn, 2)
Else
Exit For
End If
Next i
Else
strType = "UPS"
End If
CurrentDb.Execute _
"INSERT INTO TrackNum_Table(TrackingNum_TrackNum, Type_TrackNum) " & _
"VALUES ('" & strIn & "', '" & strType & "')"
Ok so a guy at work has a little access database he uses to keep track of things. He has this form that he uses that already queries what he needs and produces the results on a form and that is really all he needs.
One thing is that he has duplicates for every record that comes up with a different "Type" as a field "indentifier" (what I call it)...here is an example:
ID Name Price Type
1 Prodcut A $10 A1
1 Product A $10 A2
1 Product A $10 A3
2 Product B $12 A1
etc
naturally this is supposed to occur and he wants to see all the types but given it ends up being a mile long, he asked me if there was a way to concatenate the "types" so the following would be displayed:
ID Name Price Type
1 Prodcut A $10 A1, A2, A3
1 Product B $12 A1, A2, A3
1 Product C $14 A1, A2, A3
2 Product D $7 A1, A2, A3
...on the form. Can anyone please help me with this? Thanks!
OK, i found a function created in the VBA, which can be used in the query to retrieve the data for the form.
function is
Public Function ConcatRelated(strField As String, _
strTable As String, _
Optional strWhere As String, _
Optional strOrderBy As String, _
Optional strSeparator = ", ") As Variant
On Error GoTo Err_Handler
'Purpose: Generate a concatenated string of related records.
'Return: String variant, or Null if no matches.
'Arguments: strField = name of field to get results from and concatenate.
' strTable = name of a table or query.
' strWhere = WHERE clause to choose the right values.
' strOrderBy = ORDER BY clause, for sorting the values.
' strSeparator = characters to use between the concatenated values.
'Notes: 1. Use square brackets around field/table names with spaces or odd characters.
' 2. strField can be a Multi-valued field (A2007 and later), but strOrderBy cannot.
' 3. Nulls are omitted, zero-length strings (ZLSs) are returned as ZLSs.
' 4. Returning more than 255 characters to a recordset triggers this Access bug:
' http://allenbrowne.com/bug-16.html
Dim rs As DAO.Recordset 'Related records
Dim rsMV As DAO.Recordset 'Multi-valued field recordset
Dim strSql As String 'SQL statement
Dim strOut As String 'Output string to concatenate to.
Dim lngLen As Long 'Length of string.
Dim bIsMultiValue As Boolean 'Flag if strField is a multi-valued field.
'Initialize to Null
ConcatRelated = Null
'Build SQL string, and get the records.
strSql = "SELECT " & strField & " FROM " & strTable
If strWhere <> vbNullString Then
strSql = strSql & " WHERE " & strWhere
End If
If strOrderBy <> vbNullString Then
strSql = strSql & " ORDER BY " & strOrderBy
End If
Set rs = DBEngine(0)(0).OpenRecordset(strSql, dbOpenDynaset)
'Determine if the requested field is multi-valued (Type is above 100.)
bIsMultiValue = (rs(0).Type > 100)
'Loop through the matching records
Do While Not rs.EOF
If bIsMultiValue Then
'For multi-valued field, loop through the values
Set rsMV = rs(0).Value
Do While Not rsMV.EOF
If Not IsNull(rsMV(0)) Then
strOut = strOut & rsMV(0) & strSeparator
End If
rsMV.MoveNext
Loop
Set rsMV = Nothing
ElseIf Not IsNull(rs(0)) Then
strOut = strOut & rs(0) & strSeparator
End If
rs.MoveNext
Loop
rs.Close
'Return the string without the trailing separator.
lngLen = Len(strOut) - Len(strSeparator)
If lngLen > 0 Then
ConcatRelated = Left(strOut, lngLen)
End If
Exit_Handler:
'Clean up
Set rsMV = Nothing
Set rs = Nothing
Exit Function
Err_Handler:
MsgBox "Error " & Err.Number & ": " & Err.Description, vbExclamation, "ConcatRelated()"
Resume Exit_Handler
End Function
and is used in the query as
SELECT Table1.ID, Table1.ProductName, Table1.ProductPrice, ConcatRelated("Type","Table1","ID = " & [Table1]![ID] & " AND ProductName = """ & [Table1]![ProductName] & """ AND ProductPrice = " & [Table1]![ProductPrice]) AS Expr1
FROM Table1
GROUP BY Table1.ID, Table1.ProductName, Table1.ProductPrice, ConcatRelated("Type","Table1","ID = " & [Table1]![ID] & " AND ProductName = """ & [Table1]![ProductName] & """ AND ProductPrice = " & [Table1]![ProductPrice]);
I found an example (here) that seems to be exactly what you are looking for:
Concatenate Column Values from Multiple Rows into a Single Column with Access
From the above link:
The Problem
Coming up with a meaningful title for
this article was the hardest part. The
issue is one that I have seen a couple
times in the Access newsgroups, but it
is hard to describe without a specific
example. One post to
comp.databases.ms-access some years
ago put it this way:
I would like to combine a field's values from multiple records in a single field. For example:
Last First Code
------- --------- ----
Lesand Danny 1
Lesand Danny 2
Lesand Danny 3
Benedi Eric 7
Benedi Eric 14
Result should look like:
Last First Codes
------- --------- -----
Lesand Danny 1,2,3
Benedi Eric 7,14
Something on these lines may suit, but concatenating is usually not a good idea:
Function ConcatList(strSQL As String, strDelim, _
ParamArray NameList() As Variant)
''Reference: Microsoft DAO x.x Object Library
Dim db As Database
Dim rs As DAO.Recordset
Dim strList As String
Set db = CurrentDb
If strSQL <> "" Then
Set rs = db.OpenRecordset(strSQL)
Do While Not rs.EOF
strList = strList & strDelim & rs.Fields(0)
rs.MoveNext
Loop
strList = Mid(strList, Len(strDelim) + 1)
Else
strList = Join(NameList, strDelim)
End If
ConcatList = strList
End Function
FROM: http://wiki.lessthandot.com/index.php/Concatenate_a_List_into_a_Single_Field_(Column)
Why don't you try the "crosstab query" solution?