Find data location based on Primarykey ID - vba

I am very new to access and vba so apologies in advance for glaring conceptual gaps.
Basically I have a button that, when clicked, prompts a user to enter an ID number. The ID entered will correspond to one of my primary keys in a specific table (I have some checks in place to make sure the entered ID is valid).
I need my code to identify the row number of the ID entered and be able to populate a specific column in that row. I know Access does not refer to data locations using rows/cols but that is the best way I thought to describe it.
I am using Index/Seek/NoMatch to make sure the entered ID number is valid and I have been trying to find a way to also use those functions to generate the data location but have not had any luck. Any help would be greatly appreciated.

I think DLookup() function will work for your case. Suppose you have following dataset in table tblEmpInfo where EmpID is primary key field.
If you want to return employee name by entering employee id in a inputbox then use DLookup() like below-
Private Sub cmdDataLookup_Click()
Dim strEmpName As String, InputID As String
InputID = InputBox("Enter employee ID:", "Input ID")
strEmpName = DLookup("EmpName", "tblEmpInfo", "EmpID= '" & InputID & "'")
MsgBox strEmpName
End Sub
If you want to update any name by entering EmpID then use UPDATE SQL statement. Try below.
Private Sub cmdUpdateInfo_Click()
Dim strSQL As String, InputID As String
InputID = InputBox("Enter employee ID:", "Input ID")
strSQL = "UPDATE tblEmpInfo Set EmpName= 'Updated Value' WHERE EmpID= '" & InputID & "'"
CurrentDb.Execute strSQL
End Sub
Note: There is no direct way to get row number and column number of a Field in access but you can apply some trick by VBA to get row and column number of a Field. I will suggest to ask a separate question to get that.

Related

Displaying a field associated with a max date value record

I am working on an MS Access database and have been trying to get an unbound field on a main navigation form to display the LastUserChange that is associated with the record that was last updated.
I have used DMax() to identify the record that was most recently updated, but I can't seem to get the user ID associated with that record to display. I have a field in the table with the date timestamp that stores the user ID with it, so the data is saved in the same table. The code that I have been working on is as follows:
Private Sub Form_Load()
Dim strSQL As String
strSQL = "SELECT tblstatusupdate.LastUserChange" & _
"FROM tblstatusupdate " & _
"WHERE tblstatusupdate.LastChangeDate = DMax("LastChangeDate", "tblStatusUpdate")"
DoCmd.RunSQL strSQL
Me.LastUpdateBy = strSQL
End Sub
The code that I used to get the date of the most recently updated record is:
= DMax("LastChangeDate", "tblStatusUpdate")
Can someone please help me?
Often a mistake of new users in MS Access, DoCmd.RunSQL is reserved for action queries (i.e., INSERT, DELETE, UPDATE, ALTER, CREATE) and not SELECT queries that return a resultset.
However, for your needs consider running nested domain functions in VBA without any SQL calls. DLookUp looks up user with the criteria that its change date matches the max value of table using Dmax. Date literals must be enclosed with # characters and not quotes.
Me.LastUpdatedBy = DLookUp("LastUserChange", "tblStatusUpdate", "LastChangeDate = #" _
& DMax("LastChangeDate", "tblStatusUpdate") & "#")

How to use a INSERT INTO SELECT query in Access VBA?

I have one table called Student, which contains information on a student such as their name.
Another table called Exam which has a date the exam was taken and the name of a student as the primary key.
I have a form that can be used to select multiple students from a list box that will then be inserted into the Exam table on the date selected.
I believe my syntax is correct because if I use Access's query builder and copy/paste my SQL query and get rid of the form stuff it will work as expected.
The error I get when I try to run it from VBA is that Exam.Exam_Date is unknown and to check my spelling. I spell it how it is spelled in the table.
Is it possible to use an INSERT INTO SELECT query within VBA in Access?
Here is my code:
Private Sub add_Click()
Dim Students As String
Dim i As Integer
Dim dbs As DAO.Database
Dim SQL As String
SQL = ""
Students = "'"
For i = 0 To Me.StudentListBox.ListCount - 1
'check to see if students name is selected
If Me.StudentListBox.Selected(i) = True Then
'list student names in a string separated by commas
Students = Students + CStr(Me.StudentListBox.ItemData(i)) & "','"
End If
Next
If IsNull(Me.ExamDate) Then 'check if user entered an Exam date
MsgBox "Please select a date for the Exam."
ElseIf Students = "'" Then 'check if user selected ant Students
MsgBox "Please select Students to add to an Exam."
Else
'remove trailing comma
Students = Left(Students, Len(Students) - 2)
'sql query to add list of Students to an Exam on specified date
SQL = "INSERT INTO Exam (Exam.Exam_Date, Exam.Student_Name) SELECT '" & CDate(Me.ExamDate) & "', Students.Full_Name FROM Students WHERE Students.Full_Name IN (" & Students & ");"
DoCmd.RunSQL SQL
End If
End Sub
I understand you may have already found your issue but I do want to point out some other items.
It is a very interesting setup building the WHERE IN clause. Alternatively, you could have iterated an INSERT INTO ... VALUES inside the For/Next loop:
INSERT INTO Exam (Exam_date, Student_Name)
VALUES(#" & Me.ExamDate & "#, '" & Me.StudentListBox.ItemData(i) & "')
Also check your Exam_Date field. From your query it looks like you retain date as a string field but if date/time field, VBA queries require # # instead of single quotes. Also no need for conversion functions, CStr or CDate, if already formatted to these date types by the form.
Finally, for database design recommendation, you should use StudentID inside the Exam table instead of relating both tables by Full_Name: better indexing, primary/foreign key referential integrity, data storage efficiency. Plus, if names have quotes no need for escaping or misspellings and integer values is safer in managing data between tables (i.e., duplicates, lookup).

Access query updatable fields with group by

I want to create a split form based on a query where the fields are all grouped. The split form will not let me update the records because they are grouped. For instance let's say 10 records all had the same data in a field called "Company Name". Is there any way to make the query updatable such that when I change the data for "Company Name" on the grouped entry it will change for all of the records that are grouped?
Thanks
it is definitively not possible to update a grouped query.
The reason is, that a grouped query cannot contain the key (if you include it, you have no more a grouping, as the key is unique ...)
So Access has no clue, what is grouped and which records should be updated
What you have to do is:
create a form based on the query
add an event "on double-click" to the field you want to change
program a dialog to ask for new value
fire an sql to update
here a sample for steps 2-4
Private Sub DOK_DokumentNr_DblClick(Cancel As Integer)
Dim newvalue As Variant
Dim sSQL As String
newvalue = InputBox("enter new value", "DOC-Number", Me!DOK_DokumentNr.OldValue)
If newvalue <> Me!DOK_DokumentNr.OldValue Then
sSQL = "UPDATE T_Dokument SET DOK_DokumentNr = '" & newvalue & "' "
sSQL = sSQL & "WHERE DOK_DokumentNr = '" & Me!DOK_DokumentNr.OldValue & "'"
DoCmd.SetWarnings False ' to prevent the standard message for modifying data
DoCmd.RunSQL sSQL
DoCmd.SetWarnings True ' reset warnings to default
End If
End Sub

MS Access: Trying to select a value in a record corresponding to a certain value

Sorry if the title is confusing. But I have a table with a few different columns. One column is the KitNumber and the other is the ReturnDate. I am trying to select the value of the ReturnDate to see what the length of the entry is (also, does VBA let you get the length of a date?). What I need to do though, is the user will enter a number in an unbound, and then that value will look in the table to see if it matches another value in there, and if it does, it will select the return date. Here is the code I have now:
strSQL = "SELECT ReturnDate FROM Crew WHERE KitNumber = " & Me.AssignKit
Debug.Print strSQL
DateLen = Len(strSQL)
So say I enter '111111' in the unbound. I want it to look in the table then to see if there is a matching number. Then if there is it should return the ReturnDate value and get the length of it. Cause right now the Debug just returns the KitNumber instead of the date. Anyone be able to help me out? Thank you
If it's a one off, then a DLookup in the OnExit or OnChange events should give you the info you need to work with
using your example,
Debug.Print DLookup("ReturnDate","Crew","KitNumber = " & Me.AssignKit)
if KitNumber is stored as a string in the database, then you would need to put quotes around the selection
Debug.Print DLookup("ReturnDate","Crew","KitNumber = '" & Me.AssignKit & "'")
Note that DLookup returns the first one it finds, so if you need multiple values, you will have to look into recordset functions .Find and .FindNext

MS access SELECT INTO in vba

I'm having some issues with some functionality of my application. There is a particular instance where I have an instance of a 'pending class' on a form for an administrator to review. The form is populated with students associated with this pending class. After their grades are finished, I have a button at the footer that will delete this class from my 'pending' table and add the grades to all of the students. This works.
However, I want to essentially copy this pending class, which just has the class name, date, and teacher to a completed class table before it's deleted from pending. Since no data about this class other than the primary key(class number) persists throughout this form, I can't populate the other fields(class name, date) of the row into my completed class table.
I am trying a "SELECT INTO" operation in VBA to get these values. It's going like this:
dim cname as String
dim classdate as Date
dim pid as integer
dim teacher as String
dim qry as String
pid = [Forms]![frmClasses]![txtID]
qry = "Select className INTO cname FROM tblPending WHERE tblPending.id = " & " ' " & pid & " ' " & ";"
db.execute qry
debug.print qry
debug.print cname
From here, I do the same operations for each other variable, build my INSERT query, and execute it. The problem is-- my select into's are not working. Debug.print shows that the local variables were never initialized from the SELECT INTO statement. Any thoughts?
First, having all classes in one table and just setting a "NotPending" or "Completed" column would be better.
Having two identical tables for classes and moving values from one into the other to indicate status changes is bad database design.
If you really need to do this by using two tables and copying rows, then you need an INSERT INTO query (and not SELECT INTO), as already mentioned by Remou in the comments, because SELECT INTO creates a new table (or overwrites an existing one with the same name, if already there).
The syntax for INSERT INTO looks like this:
INSERT INTO CompletedClassTable (ClassName, Teacher)
SELECT ClassName, Teacher FROM tblPending WHERE id = 123
And finally, you asked this in a comment:
So SELECT INTO is completely different in Access than Oracle? In Oracle and PL/SQL, you can select a row into a variable OR a table. In Access can you not select into a variable?
To load a row into a variable, you need to use a Recordset.
Example code to load your query into a Recordset and output the ClassName field:
Dim RS As DAO.Recordset
Set RS = CurrentDb.OpenRecordset("SELECT * FROM tblPending WHERE id = 123")
If Not RS.EOF Then
Debug.Print RS("classname")
End If
RS.Close
Set RS = Nothing
Seems you want to retrieve a text value, className, from tblPending where tblPending.id matches the value found in your text box, txtID, and store that text value in a string variable named cname.
If that interpretation is correct, you needn't bother with a query and recordset. Just use the DLookup Function to retrieve the value, similar to this untested code sample.
Dim cname As String
Dim pid As Integer
Dim strCriteria As String
pid = [Forms]![frmClasses]![txtID]
strCriteria = "id = " & pid
cname = Nz(DLookup("className", "tblPending", strCriteria), vbNullString)
Debug.Print "cname: '" & cname & "'"
Notes:
I assumed the data type of the id field in tblPending is numeric. If it is actually text data type, change strCriteria like this:
strCriteria = "id = '" & pid & "'"
DLookup() returns Null if no match found. Since we are assigning the function's return value to a string variable, I used Nz() to convert Null to an empty string. Alternatively, you could declare cname As Variant (so that it can accept a Null value) and get rid of Nz().