Using Null in a DLookup Criteria - ms-access

I am creating a database to manage the flow of people in and out of an incident system. My idea is to use the DLookup function to allow me to identify a null value in the checkout date. This would allow me to prevent someone from jumping incidents without signing out first.
If it is possible I would like to get the EVENT ID and the COMMAND POST ID so I can create an error message to tell me the incident that is member is still attached to.
'***Section 1 - Ensure member is Checked out and DEMOBed from previous incidents
'******Variables
'*********Variable to hold the Member ID
Dim id As Integer
'*********Variable to hold the checkout status
Dim checkout As String
'*********Variable to hold the Event ID
Dim eventID As Integer
'******Code Block 1 - Check for Null Values
id = Me.Text18
Forms![frm_ics238Table].Refresh
If Not IsNull(DLookup("[eventID]", "[frm_ics238Table]", "[checkoutDate] is Null And employeeID = '" & Me.Text18 & "'")) Then
MsgBox "y"
End If
End Sub

From your original question which right now it doesn't look like you've edited it to indicate the updated code and errors, you had:
id = Me.Text18
Forms![frm_ics238Table].Refresh
If Not IsNull(DLookup("[eventID]", "[frm_ics238Table]", "[checkoutDate] is Null And employeeID = '" & Me.Text18 & "'")) Then
MsgBox "y"
End If
I think these might help:
"[frm_ics238Table]" should be table:"[tbl_ics238Table]"
ID appears to be declared as an integer yet you're using it as a
string. If employeeID is actually a numeric field remove the quotes
around employeeID = '" & Me.Text18 & "'" It should look like this employeeID = " & ID & "
You can also try using IsNull([checkoutDate]) instead of
[checkoutDate] is Null
SO it might look like:
If Not IsNull(DLookup("[eventID]", "[tbl_ics238Table]", "IsNull([checkoutDate]) And (employeeID = " & ID & ")")) Then
MsgBox "y"
End If
Even better would be to put the criteria into a string variable so you could debug and test it first
Dim strCriteria as String
strCriteria = "IsNull([checkoutDate]) And (employeeID = " & ID & ")"
Debug.Print strCriteria
If Not IsNull(DLookup("[eventID]", "[tbl_ics238Table]", strCriteria)) Then
MsgBox "y"
End If
EDIT: PROOF OF WORKING CODE:
Not that I don't believe you but I don't believe that it doesn't work if what you've described matches my assumptions.
I tested successfully using assumptions that:
eventID - number field
checkoutDate - date/time field
employeeID - number field
My sample data table
Then I put a command button on a form to test the code:
Private Sub Command8_Click()
Dim strCriteria As String
Dim ID As Integer
ID = 4
strCriteria = "IsNull([checkoutDate]) And (employeeID = " & ID & ")"
Debug.Print strCriteria
If Not IsNull(DLookup("[eventID]", "[tbl_ics238Table]", strCriteria)) Then
MsgBox "y"
End If
End Sub
Finally - testing the button click resulted in:
In conclusion - if you're still getting an error then you can update
your question with BOTH your code AND your table design.

Related

Table showing "Wrong" Record, but Query returns "Correct" data?

Alright, so here's what happened :
I had a wide table, that needed to be a long table. I used the code below (CODE 1) to fix that problem:
It seemed to have worked, though I am now finding minor errors in the data, while I will need to resolve those, that isn't what this question is about.
In the end, my table looks correctly, and here is an actual record from the database, in fact it is the record that called my attention to the issues:
tbl_CompletedTrainings:
ID
Employee
Training
CompletedDate
306
Victoria
Clozaril
5/18/2016
306
20
8
5/18/2016
the second row is to show what the database is actually seeing (FK with both Employee and Training tables) Those tables have the following formats:
tbl_employeeInformation:
ID
LastName
FirstName
Address
Line2
City
State
Zip
Site1
Site2
Site3
20
A.
Victoria
6 Street
City
State
00000
3NNNN
4
Eric
A.
15 Street
City
State
00000
3nnnnn
tbl_Trainings:
AutoID
TrainingName
Expiration
6
Bloodborne
Annual
8
Clozaril
Annual
When the query in (CODE 2) is run on this table, the following record is returned
report Query:
LastName
FirstName
Training
CompletedDate
Site1
Site2
Site3
ID
Accccc
Eric
Bloodborne Pathogens
5/18/2016
3NN-NN
N/A
N/A
306
Notice that the ID in the report Query is only there as I was checking records, and is called from the tbl_CompletedTrainings. So here's the question, What is happening?! If the record was just wrong, and not pulled I could understand it, but that's not what's happening. Worse still is the date is the correct date for the training the query returns, but not for the training listed in the table.
Related issue, possibly, I had noticed that when I queried the table with a call on the foreign key, it returns records that are 2 off of the requested training number. Notice that this is the case here as well. The training listed, Clozaril, is exactly two further down the line than the training Bloodborne Pathogens, Key 8 and 6 respectively.
Any help would be very much appreciated in this matter, as I can't seem to catch what is causing the issue. Yet it must be something.
(CODE 1)
Option Compare Database
Option Explicit
Sub unXtab()
On Error GoTo ErrHandler
Dim db As DAO.Database
Dim rsxtab As DAO.Recordset
Dim rsutab As DAO.Recordset
Dim counter As Integer
Dim loopint As Integer
Dim qryGetNameID As DAO.Recordset
Dim qryGetTrainingNameID As DAO.Recordset
Dim expires As Date
Dim namevar As String
Dim lname As String
Dim fname As String
Set db = CurrentDb
Set rsxtab = db.OpenRecordset("SELECT * FROM [Employee Training Log];")
If Not (rsxtab.BOF And rsxtab.EOF) Then
db.Execute "DELETE * FROM tbl_CompletedTrainings;"
Set rsutab = db.OpenRecordset("SELECT * FROM tbl_CompletedTrainings WHERE 1 = 2;")
counter = rsxtab.Fields.Count - 1
Do
For loopint = 2 To counter
namevar = rsxtab.Fields(loopint).Name
lname = rsxtab("[Last Name]")
fname = rsxtab("[First Name]")
Select Case namevar
Case "First Name"
Case "Last Name"
Case "Date of Hire"
Case Else
If rsxtab.Fields(loopint) <> "" Or Not IsNull(rsxtab.Fields(loopint)) Then
Set qryGetTrainingNameID = db.OpenRecordset("SELECT AutoID FROM Trainings WHERE [Training Name] = " & Chr(34) & namevar & Chr(34) & ";")
Set qryGetNameID = db.OpenRecordset("SELECT ID FROM tbl_EmployeeInformation WHERE LastName = " & Chr(34) & lname & Chr(34) & _
" AND " & Chr(34) & fname & Chr(34) & ";")
rsutab.AddNew
Debug.Print lname
Debug.Print fname
Debug.Print namevar
Debug.Print qryGetNameID.Fields(0)
Debug.Print qryGetTrainingNameID.Fields(0)
rsutab.AddNew
rsutab("Employee") = qryGetNameID.Fields(0)
rsutab("Training") = qryGetTrainingNameID.Fields(0)
rsutab("CompletedDate") = rsxtab.Fields(loopint)
rsutab.Update
End If
End Select
Next loopint
rsxtab.MoveNext
Loop Until rsxtab.EOF
End If
exitSub:
On Error Resume Next
rsxtab.Close
rsutab.Close
Set rsxtab = Nothing
Set rsutab = Nothing
Set db = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Number & " : " & Err.Description & vbCrLf & vbCrLf & " on this field: " & namevar, vbOKOnly + vbCritical
End Sub
(CODE 2)
SELECT EI.LastName, EI.FirstName, T.TrainingName AS Training, CT.CompletedDate, EI.Site1, EI.Site2, EI.Site3, CT.ID
FROM tbl_EmployeeInformation AS EI
INNER JOIN (tbl_CompletedTrainings AS CT
INNER JOIN tbl_Trainings AS T ON CT.Training = T.AutoID) ON EI.ID = CT.Employee;

MS Access 2010 value of MemberID where FinishDate = NULL

Using MS Access 2010
My Table BranchMemberOffice has the following columns:
BranchID
OfficeID
MemberID
FinishDate
Below works but I need the value of MemberID where FinishDate = NULL
strBranchID = Combo221.Column(0)
strOfficeID = 1
strChair = DLookup("MemberID", "BranchMemberOffice", "BranchID = " & strBranchID & " AND OfficeID = " & strOfficeID)
Hope I am clear enough :)
If your table structure is like this (I've not added any Primary Keys):
This code will return MemberID 11:
Sub Test()
Dim MemberID As Variant 'Changed from Long to accept Nulls.
Dim lOfficeID As Long
Dim lBranchID As Long
lOfficeID = 3
lBranchID = 1
MemberID = DLookup("MemberID", "BranchMemberOffice", _
"BranchID=" & lBranchID & " AND OfficeID=" & lOfficeID & _
" AND FinishDate Is Null")
If IsNull(MemberID) Then
MsgBox "No value returned."
Else
MsgBox MemberID & " is the value returned."
End If
End Sub
Edit: Nearly forgot - MemberID in the code above must be defined as a Variant. Keeping it as a Long will return "Invalid use of Null" if the result is Null - a Long can't hold a Null value, while a Variant can.
Edit 2: Have added a message box to show how to deal with Null values.
Try this:
strChair = DLookup("MemberID", "BranchMemberOffice", "FinishDate Is Null")

How to avoid a "You must enter a value" error message in Access VBA

I'm having issues avoiding a "You must enter a value in the __ field" error message in Access 2016. I have three tables, Tasks, Users, and TaskAssignments, and a split form that looks like:
User Task Assigned?
User1 Task1 True
User1 Task2 False
User1 Task3 True
User2 Task1 False
User2 Task2 False
User2 Task3 True
User3 Task1 True
User3 Task2 True
User3 Task3 True
Each task can have multiple users assigned to it, and each user is assigned to multiple tasks. I want my form to display every possible value, then use a checkbox, so that I can click and add a user to that task. The TaskAssignments table has a primary key and a unique constraint on both TaskID and UserID.
The recordsource for my form is a query:
select x.UserName, x.TaskName, ta.is_assigned
from (select * from Tasks, Users) x
left join TaskAssignments ta on (ta.TaskID = x.TaskID and ta.UserID = x.UserID)
I have an on click event that checks if a record exists in TaskAssignments and either updates or inserts into TaskAssignments. When I debug.print and manually run my queries, they both do what's expected. When I manually insert a record into my TaskAssignments table, my form behaves how I expect. When I need to insert a new record, however, I receive a message stating that I must enter a TaskID in TaskAssignments.
I've tried requerying the form, but I still receive the error message. Why can't it find the record that I just inserted?
Help please?!? Do I need to drastically rethink my approach here?
Here's the VBA:
Private Sub is_assigned_Click()
Dim CurrentUser, AssignmentQuery As String, SelectedUserID, SelectedTaskID As Integer
Dim ShouldInsert, IsAssigned As Boolean
CurrentUser = Environ$("Username")
SelectedUserID = Me.UserID
SelectedTaskID = Me.TaskID
IsAssigned = Me.is_assigned
Dim db As DAO.Database, rs As DAO.Recordset, strSQL As String
Set db = CurrentDb
strSQL = "select UserID, taskID from TaskAssignments where UserID=" & SelectedUserID & " and taskID =" & SelectedTaskID & ";"
Set rs = db.OpenRecordset(strSQL)
If rs.EOF = True Then
ShouldInsert = True
Else: ShouldInsert = False
End If
If ShouldInsert = True Then
AssignmentQuery = "insert into TaskAssignments (UserID, taskID, DateAssignmentUpdated, AssignmentUpdatedBy, is_assigned) values " _
& vbCrLf & "(" & SelectedUserID & "," & SelectedTaskID & ",#" & Now & "#,'" & CurrentUser & "'," & IsAssigned & ");"
ElseIf ShouldInsert = False Then
AssignmentQuery = "update TaskAssignments set UserID=" & SelectedUserID & ", DateAssignmentUpdated=#" & Now & "#, AssignmentUpdatedBy='" & CurrentUser & "',is_assigned=" & IsAssigned _
& vbCrLf & " where taskID = " & SelectedTaskID & " And UserID = " & SelectedUserID & ";"
End If
MsgBox AssignmentQuery
db.Execute (AssignmentQuery)
Forms("Task Assignments").Requery
Set rs = Nothing
Set db = Nothing
End Sub
Edit - here are the queries produced:
Insert
insert into TaskAssignments
(UserID, TaskID, DateAssignmentUpdated, AssignmentUpdatedBy, is_assigned)
values (301,4,Now(),'mylogin',True);
Update
update TaskAssignments
set UserID=270, DateAssignmentUpdated=Now(), AssignmentUpdatedBy='mylogin', is_assigned=False
where TaskID = 1 And UserID = 270;
And a constraint on my TaskAssignments table. Both TaskID and UserID are set as required in my table design (which was my whole goal - I was hoping to avoid adding records to TaskAssignments until the user has actually been assigned to a task).
alter table TaskAssignments add constraint TaskAssignmentsConstraint unique (TaskID, UserID);
Beware of wrong datatypes, each Dim needs its own datatype!
Dim CurrentUser As String, AssignmentQuery As String
Dim SelectedUserID As Long, SelectedTaskID As Long ' don't use 16-bit Integer for ID columns
Dim ShouldInsert As Boolean, IsAssigned As Boolean
To avoid troubles with date/time formatting: the database engine knows Now(), so you can directly use this in the Insert SQL:
AssignmentQuery = "insert into TaskAssignments (UserID, taskID, DateAssignmentUpdated, AssignmentUpdatedBy, is_assigned) values " _
& vbCrLf & "(" & SelectedUserID & "," & SelectedTaskID & ", Now(), '" & CurrentUser & "'," & IsAssigned & ");"
If it still doesn't work, use Debug.Print AssignmentQuery instead of MsgBox and add the actual SQL to your question (Ctrl+G shows the output).
Edit
Re-reading the question and comment, I think the problem is:
You are editing a bound form, and are updating/inserting in the same table the form is based on. That's where the Write conflict on Update comes from, the other error is probably because the bound form is trying to insert a record when you click is_assigned, but can't.
So yes, you need to rethink your approach, at least partially.
One solution is to insert the recordsource into a temp table, and base your form on that. Then the rest of the code will probably work.
It may be over-complicating things, though.
I got this problem trying to update a field that use to be a primary field in my table. When I altered what was considered the primary field I assume access would automatically stop enforcing is not null, but for some reason it didn't.
I fixed it by deleting the field, saving the table recreating the field and saving the table and the problem went away. Of course this wouldn't be an ideal solution if you have data in that table you don't want to lose so you might want to try backing it up first, before you give the solution a try, then reinserting the values.

VBA Access getting RowSource to find lookup values

VBA noob here (as of this mourning),
In MS Access I wrote a test function to find the value of a record base on some criteria you pass in.
The function seems to work fine except in cases where there is a lookup in the column that I am searching.
Basically it might return "19" and 19 corresponds to some other table value.
It seems that the RowSource of the column is what Im after so I can do a second query to find the true value.
Can someone point me in the right direction on finding the RowSource assuming I know the column name and then utilizing it to find the value Im after?
Edit: It seems that Im not explaining myself clearly, Here is a picture of what I trying to get programatically
Try this -- I think I finally understand why you are looking for the RowSource -- sorry I didn't "get" it at first. The field you're trying to pull is a foreign key into a description table.
This function should work as a general solution for all such fields (assuming the RowSource always has the primary key first, and the description second). If there is no RowSource, it will just pull the value of the field.
It's based on your original code, rather than the changes proposed by #ron, but it should set you in the right direction. You should fix it to make it parameterized, and allow for variant data types, as ron suggests (+1 ron)
As an aside, use the ampersand (&) to join strings together in VBA to avoid things like this: abc = "1" + 1, where abc is now equal to 2 instead of "11" as you would expect if both items were intended to be strings.
Public Function lookUpColumnValue(Database As Database, column As String, table As String, lookUpColumn As String, lookUpValue As String) As String
Dim sql As String
Dim recordSet As DAO.recordSet
Dim result As String
lookUpColumnValue = "" 'Return a blank string if no result
On Error Resume Next
sql = "SELECT [" & table & "].[" & column & "] FROM [" & table & "] WHERE [" & table & "].[" & lookUpColumn & "] = '" & lookUpValue & "'"
Set recordSet = Database.OpenRecordset(sql)
If Not recordSet.EOF Then
Dim td As DAO.TableDef
'this gives your number - say, 19
result = recordSet(column)
Set td = Database.TableDefs(table)
'Get the rowsource
Dim p As DAO.Property
For Each p In td.Fields(column).Properties
If p.Name = "RowSource" Then
RowSource = Replace(td.Fields(column).Properties("RowSource"), ";", "")
Exit For
End If
Next
If Not RowSource = "" Then
Dim rs2 As DAO.recordSet
Dim qd As DAO.QueryDef
Set qd = Database.CreateQueryDef("", RowSource)
Set rs2 = Database.OpenRecordset(RowSource)
If rs2.EOF Then Exit Function
PKField = rs2.Fields(0).Name
rs2.Close
qd.Close
sql = "SELECT * FROM (" & RowSource & ") WHERE [" & PKField & "]=[KeyField?]"
Set qd = Database.CreateQueryDef("", sql)
qd.Parameters("KeyField?").Value = result
Set rs2 = qd.OpenRecordset()
If Not rs2.EOF Then
'NOTE: This assumes your RowSource *always* has ID first, description 2nd. This should usually be the case.
lookUpColumnValue = rs2.Fields(1)
End If
Else
'Return the field value if there is no RowSource
lookUpColumnValue = recordSet.Fields(column)
End If
End If
End Function
If I understand your question correctly, I think using a parameter query will solve your problem. Using parameters is good practice since they will perform implicit data type casts and also prevent injection attacks.
Notice in the following function, I changed the lookupValue to a Variant type, which allows you to pass any type of value to the function.
Public Function lookUpColumnValue( _
database As DAO.database, _
column As String, _
table As String, _
lookUpColumn As String, _
lookUpValue As Variant) As String
Dim sql As String
Dim recordSet As DAO.recordSet
Dim result As String
Dim qd As QueryDef
Set qd = database.CreateQueryDef("")
sql = "SELECT [" + table + "].[" + column + "] FROM [" + table + "] " & _
"WHERE [" + table + "].[" + lookUpColumn + "] = [parm1];"
qd.sql = sql
qd.Parameters![parm1] = lookUpValue
Set recordSet = qd.OpenRecordset()
result = recordSet(column)
EDIT
lookUpColumnValue = DLookup("Space Use Description", "Space Use Codes", result)
End Function

A "Count" Based off Filters set in a Pivot Table

So, we have imported data which we have queried and then created a pivot table off that query. It is essentially a list of files, each having unique ID numbers, and various attributes (file extension, type of document, hash, etc). In any case, this data is based off "hits" on keyword searches from a different program. This means that there might be multiple records for the same Unique ID since there are multiple hits.
The pivot table allows us to illustrate/manipulate via filtering out certain criteria (e.g. we don't want certain file extensions or we don't want records with FIELD X or FIELD Y0. The report is fine, but we want to make a form/query/report/whatever that will pull a "count" (based off unique ID) which ignores duplicates. For example, once all the filters are set in the pivot table, based on the filters/output of the pivot table, we want something like this:
.PDF Files: 200 | total for field x | total field y | etc
.DOCX files: 320 | total for field x | total for field y | etc
Obviously, we want to ignore duplicates of the same Unique ID in the counts.
What is the best way to do this considering we will be manipulating the pivot table dynamically and often? The ideal scenario would to have the pivot table and another object (form/report/etc) open, and as the pivot table is manipulated whatever is displaying counts changes as well.
Here are some very rough notes notes. They are only minimally tested, and using IN would be a disaster with a lot of values, however, it would be easy enough to switch this round and use an excluded list. Perhaps you can get some ideas.
Dim oPTable ''PivotTable
Dim oPM ''PivotMember
Dim oFUpd ''PivotFilterUpdate
Dim oChildren ''ChildMembers
Dim fset ''FieldSet
Dim sWhere As String
Dim sTemp As String
Dim sSQL As String
Dim sDelim As String
Dim aStates As Variant
Dim i As Integer
Dim rs As DAO.Recordset
sDelim = """"
aStates = Array("Cleared", "Checked") ''Possible states
Set oPTable = Forms(0).PivotTable.ActiveView
sWhere = vbNullString
For Each fset In oPTable.FieldSets
sTemp = vbNullString
Set oChildren = oPTable.FieldSets(fset).Member.ChildMembers
For i = 0 To oChildren.Count - 1
Set oPM = oChildren(i)
Set oFUpd = oPM.Field.FieldSet.CreateFilterUpdate
If aStates(oFUpd.StateOf(oPM) - 1) = "Checked" Then
Select Case fset.BoundField.DataType
Case adChar, adLongVarWChar
sTemp = sTemp & "," & sDelim & oPM.Caption & sDelim
Case adInteger
sTemp = sTemp & "," & oPM.Caption
Case adDate
sTemp = sTemp & ",#" & oPM.Caption & "#"
Case Else
'' The above is a very short list.
'' Stop
End Select
End If
Next
If sTemp > vbNullString Then
sWhere = sWhere _
& " AND [" & fset.Name & "] IN ( " & Mid(sTemp, 2) & ")"
End If
Next
sSQL = "SELECT DISTINCT ID FROM [" & oPTable.Control.DataMemberCaption & "] "
sSQL = sSQL & "WHERE 1=1" & sWhere
Set rs = CurrentDb.OpenRecordset(sSQL)
MsgBox "Unique: " & rs.RecordCount
if that helps:
http://lazyvba.blogspot.com/2010/11/improve-your-pivot-table-to-count.html
it will get you the unique count of ID numbers by numbers you want, and you can still manipulate the pivot