VBA loop until function is true, changing passed value each time - ms-access

I have a form that adds new users. I'm trying to auto generate the username, which needs to be unique. I have a function checkUsername that takes the string passed and checks the db table to see if that username exists. It returns false if the username exists and true if not.
What I'm trying to do is if the username already exists then add a number on to the end and check again. I want to keep looping until a unqiue username is found. Heres my attempt at a loop below, however its returning usernames that already exist. Also I prefer it to increment the number rather than just adding it to the end. Currently the pattern ends up being username1, username12, username123.
'Generate username
Dim Username As String
Username = generateUsername(LCase(Left(FirstName, 1) & LastName))
Function generateUsername(Username As String) As String
Dim i As Integer
i = 1
Do While checkUsername(Username)
If checkUsername(Username) Then
Exit Do
Else
Username = Username & i
i = i + 1
End If
Loop
generateUsername = Username
End Function

What I would do is, when the username exists already (see Andre's answer for the code that will accomplish this a different way):
check what the previous "i" number was, as a string, to see how many characters I need to cut off the end of username
set username equal to a substring of username, which will cut off the last X characters (X being the number of characters the previous "i" was)
add the new "i" to the end username
That will solve your naming issue.
For your issue of looking for unique names, no one will be able to help with that until we can see what the code looks like for the "checkUsername" function. Make sure that that function is returning the value you are expecting, first. I suspect the problem is in there.
EDIT:
I also don't understand why you have an "If/Else" statement in your loop. You already determined that it was true. See below for simplified version (again, assuming I got the code right for VB...I usually do it in C#):
Do While Not checkUsername(NewName)
NewName = Username & i
i = i + 1
Loop

I assume checkUsername() returns true if the username exists?
Then your If condition is wrong - you want to exit if it doesn't exist.
Your loop gets clearer if you use two variables:
Function generateUsername(origUsername As String) As String
Dim i As Integer
Dim Username As String
i = 1
Username = origUsername
Do While checkUsername(Username)
' If Not checkUsername(Username) Then
' Exit Do
' Else
Username = origUsername & i
i = i + 1
' End If
Loop
generateUsername = Username
End Function
Edit: as pointed out by Joel, the additional checkUsername() in the loop isn't needed. Since it probably involves a DLookup or similar, it is actually harmful to performance.
I commented it out above.

Sorry, but this is the corrected version!
Change your code to this instead:
Dim Username As String
Username = generateUsername(LCase(Left(FirstName, 1) & LastName))
Function generateUsername(Username As String) As String
Dim NewName as String
Dim i As Integer
i = 1
NewName = Username
Do While checkUsername(NewName)
If checkUsername(NewName) Then
Exit Do
Else
NewName = Username & i
i = i + 1
End If
Loop
generateUsername = NewName
End Function

Related

code ot check if data entry already exist

I have a form where the user enters data "last name"
I am trying to put a code together that checks if the data entered for "last name" already exists in a database, and if it does, for a message box to appear advising the user that the last name already exists, and then giving them the option on whether they would like to continue in adding that "last name" into the database.
ive written the code several different ways, with if statements and dlookup, but it doesn't seem to be working
Check this out
Private Sub btn_Click()
'variable declaration
Dim lastName As String
Dim cnt As Long
Dim retVal As Variant
'get textbox value into variable. Nz function checks for null and replaces it with empty string in case its nulll
lastName = Nz(Me.txtLastName, "")
'dcount function checks the count of lastname in tblUser
If DCount("*", "tblUser", "LastName='" & lastName & "'") > 0 Then
retVal = MsgBox("Name already exist. Do you want to continue?", vbYesNo)
If retVal = vbYes Then
'your insert statement
Else
'
End If
End If
End Sub

getting linked table path with tabledef.connect

I have been trying to get the path to a linked table. I am looping thru the tables. it works one the first loop but not on the 2nd loop. it returns "".
Ive tried several different ways, calling the table by name or by number. the code originally comes from Neville Turbit. Neville's code calls the table by name, but I could not get that to work.
Public Function GetLinkedDBName(TableName As String)
Dim tblTable As TableDef
Dim strReturn As String
Dim i As Integer
On Error GoTo Error_NoTable ' Handles table not found
'---------------------------------------------------------------
'
i = 0
On Error GoTo Error_GetLinkedDBName ' Normal error handling
For Each tblTable In db.TableDefs
If tblTable.Name = TableName Then
strReturn = tblTable.Connect
strReturn = db.TableDefs(i).Connect
Exit For
End If
i = i + 1
Next tblTable
You don't need a loop:
Public Function GetLinkedDBName(TableName As String) As String
Dim strReturn As String
On Error Resume Next ' Handles table not found
strReturn = CurrentDb.TableDefs(TableName).Connect
GetLinkedDBName = strReturn
End Function
This is my modification from Gustav's.
CurrentDb.TableDefs(TableName).Connect command will returns a string like this:
"MS Access;PWD=p455w0rd;DATABASE=D:\Database\MyDatabase.accdb"
The string above contains 3 information and parted by ";" char.
You need to split this information and iterate through it to get specific one which contain database path.
I am not sure if different version of ms access will return exact elements and with exact order of information in return string. So i compare the first 9 character with "DATABASE=" to get the index of array returns by Split command and get path name from it.
Public Function getLinkedDBName(TableName As String) As String
Dim infos, info, i As Integer 'infos and info declared as Variant
i = -1
On Error Resume Next ' Handles table not found
'split into infos array
infos = Split(CurrentDb.TableDefs(TableName).Connect, ";")
'iterate through infos to get index of array (i)
For Each info In infos
i = i + 1
If StrComp(Left(info, 9), "DATABASE=") = 0 Then Exit For
Next info
'get path name from array value and return the path name
getLinkedDBName = Right(infos(i), Len(infos(i)) - 9)
End Function

How to detect same data in a datagridview column?

When a user enters data into the datagrdview, the user cannot enter data that already exists in the datagridview. If the user tries to enter the same data in the datagridview (in the same column), a message box will pop up and tell them: "cannot enter same data on datagridview."
Thank you for your help.
You will need to check the input against the database to see if it is already there. For example, run the following MySQL statement to check if the input is database:
Dim userInput As String
userInput = TextBox1.Text 'an example of user input from a textbox
Dim MySQLStatement As String = "SELECT * FROM `your_table` WHERE your_column = '" & userInput & "';"
I am unable to continue the example above without knowing how you are connecting to the database, but it may be unnecessary. However you connect, you can check the record count after you have executed the MySQL statement. If it is 1 or more, than you know the data is already in your database and you can stop the user input from going into the database.
Finally I've got the solution! This is the code I used to solve the problem. My datagridview name is DataGridView3. The code are :
Private Sub DataGridView3_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView3.CellEndEdit
For Each Row As DataGridViewRow In DataGridView3.Rows
Try
If DataGridView3.Rows(e.RowIndex).Cells(0).Value.ToString <> Row.Cells(0).Value.ToString AndAlso DataGridView3.Rows(e.RowIndex).Cells(0).Value.ToString = DataGridView3.Rows(e.RowIndex).Cells(0).Value.ToString Then
ElseIf DataGridView3.Rows(e.RowIndex).Cells(0).Value.ToString = Row.Cells(0).Value.ToString Then
If Row.Cells(0) Is DataGridView3.Rows(e.RowIndex).Cells(0) Then
Else
MsgBox("Can't Duplicate Condition Data!")
DataGridView3.Rows(e.RowIndex).Cells(0).Value = ""
Exit For
End If
End If
Catch
End Try
Next
End Sub

Characters appended to a string all appear as question marks in VBA

I have been using the same code to get the fullname from the current user for a while now and it suddenly started behaving weird.
I have a string variable named CurrentUser which I populate with my function GetFullNameOfLoggedUser().
This return in the immediate window (msgbox also works fine) "Lastname, Firstname (F)" which it is supposed to.
When I want to give the variable to another string variable called 'sql1', it starts to behave weird all of a sudden:
CurrentUser = GetFullNameOfLoggedUser()
Dim sql1 As String: sql1 = "UPDATE Tbl_Records SET Tbl_Records.[Added by] = """ & CurrentUser & """ WHERE Tbl_Records.[Added by] IS NULL;"
The value of sql1 suddenly becomes:
UPDATE Tbl_Records SET Tbl_Records.[Added by] = "Lastname, Firstname (F)? ????? ?????????????????? ??? ?? ?????
Does anybody have a clue where all the question marks come from?
Disclaimer Lastname and Firstname are obviously regular values, they are omitted for the sake of privacy.
Extra info:
To get the full network name, I am using this fine piece of code from Dev Ashish which makes use of windows API:
http://access.mvps.org/access/api/api0066.htm
The function has been dimmed as string. I have added an "" at the end of the function to ensure the value is a string type:
Function GetFullNameOfLoggedUser(Optional strUserName As String) As String
...
GetFullNameOfLoggedUser = StrFromPtrW(pTmp.EUI_full_name) & ""
End Function
As seen in the locals window, it truly is a string. (This snap has been taken right before the end of the funcion, so no further changes will happen to the variable.
CurrentUser has also explicitly been defined as a string variable. Option Explicit is also active on every page.
There does seem to be something a bit strange about the string that fGetFullNameOfLoggedUser() returns. When I run the code
Dim s As String
s = fGetFullNameOfLoggedUser()
Debug.Print Len(s)
Debug.Print s
I get
13
GORD THOMPSON
which looks correct. However, if I change the last Debug.Print to
Debug.Print "|" & s & "|"
I get
|GORD THOMPSON?
with the final character being a question mark ? instead of a pipe |. However, if I Trim() the string
Debug.Print "|" & Trim(s) & "|"
then I get
|GORD THOMPSON|

LotusScript - Can anyone fix my function?

I'm trying to write a validation function that checks to see if an entry being added already exists in the dataset.
But the search doesn't pick it up - i can just keep entering the same appointment into the database.
If anyone can spot why my code isn't working, i'd appreciate the help.
Thanks
Public Function checkNewLocationRecordIsUnique As Boolean
Dim s As New NotesSession
Dim w As New NotesUIWorkspace
Dim db As NotesDatabase
Dim selectView As NotesView
Dim key(0 To 4) As Variant
Dim entry As NotesViewEntry
Dim entryIsNotUniqueMsg As String
Let entryIsNotUniqueMsg = "There is already an entry for this date/time. Please modify your entry's details or cancel the existing entry to continue."
Dim thisDoc As NotesDocument
Dim uiDoc As NotesUIDocument
Set uidoc = w.CurrentDocument
Set thisDoc = uidoc.Document
'get handle to database and check we've found the database
Set db = s.CurrentDatabase
If Not db Is Nothing Then
'get handle to view to lookup field combination in
Set selectView = db.GetView("allLocationRecordsByName")
Call selectView.Refresh()
If Not selectView Is Nothing Then
'populate "key" - an array of variants - with fields to use as match criteria
key(0) = thisDoc.PersonName
key(1) = thisDoc.StartDate
key(2) = thisDoc.EndDate
key(3) = thisDoc.StartTime
key(4) = thisDoc.EndTime
Set entry = selectView.GetEntryByKey(thisDoc.key, True)
'lookup the combination in the view to see if it already exists
If entry Is Nothing Then
MsgBox "No conflicting entry found! Record added.", 0, "Notice"
'if it wasn't found then the record is unique so return true
checkNewLocationRecordIsUnique = True
Else
'else the combination was found - but lets make sure that it's not this one
'(this could happen if the user is editing an existing record)
'compare uids of both thisDoc and the doc entry that was found
If entry.document.UniversalID = thisDoc.UniversalID Then
checkNewLocationRecordIsUnique = True
MsgBox "An Entry Was Found, But It Was The Entry! Record added.", 0, "Notice"
'else it WAS found as a separate document so the function returns false
Else
MsgBox entryIsNotUniqueMsg, 0, "Error: Entry Is Not Unique"
checkNewLocationRecordIsUnique = False
End If
End If
End If
End If
End Function
thisDoc.PersonName returns an array, you probably need to use
key(0) = thisDoc.PersonName(0)
key(1) = thisDoc.StartDate(0)
key(2) = thisDoc.EndDate(0)
key(3) = thisDoc.StartTime(0)
key(4) = thisDoc.EndTime(0)
You are using five lines of code to populate a local variant array called key, but you are not actually using that array for your GetEntryByKey call.
So my guess is that you want the code to say this:
Set entry = selectView.GetEntryByKey(key, True)
instead of this:
Set entry = selectView.GetEntryByKey(thisDoc.key, True)
Is the view allLocationRecordsByName sorted on each column included in the search key?
See GetEntryByKey documentation.