MS Access 03 Query using Yes/No Data Type - ms-access

I have a table in Access..
AccessKey
AccessCardID
Distributed (yes/no)
On my form is a combo box with 10 Access Cards. I need help setting up a query where if guest A gets Access Card #1, the user will only be able to choose from Access Cards #2-#10, for guest B, c, and so on, until guest A returns Access Card #1.
so far the the query i have is
SELECT AccessCardID
FROM AccessKey
WHERE Distributed = False;
Here is my new code for After update
Private Sub AccessKeyNo_AfterUpdate()
If MsgBox("Do you want to assign Access Key" & Me.AccessKeyNo & "?", _
vbYesNo) = vbYes Then
Me.GuestAccessKeyID = Me.AccessKeyNo
Me.MyCheckBox = Not IsNull(Me.GuestAccessKeyID)
Me.AccessKeyNo.Requery
End If
End Sub
My new query
SELECT AccessKey.AccessKeyID
FROM AccessKey LEFT JOIN Guest ON AccessKey.AccessKeyID=Guest.GuestAccessKeyID
WHERE (((Guest.GuestAccessKeyID) Is Null));
And the On current for the form
Private Sub Form_Current()
Me.MyCheckBox = Not IsNull(Me.GuestAccessKeyID)
If IsNull(Me![GuestID]) Then
DoCmd.GoToControl "GuestFirstName"
End If
End Sub

Why don't you set Distributed to False in the above query so that you get the list of cards which have not been distributed yet.

If you do not like writing code, you can use a subform and set the record source to your table, AccessKey. Alternatively you can write a little code, say:
Private Sub NameOfComboHere_AfterUpdate()
Dim db As Database
Dim strSQL As String
Set db = CurrentDb
If MsgBox("Do you want to assign " & Me.NameOfComboHere & "?", _
vbYesNo) = vbYes Then
strSQL = "UPDATE AccessKey SET Distributed = True " _
& "WHERE AccessCardID = " & Me.NameOfComboHere
db.Execute strSQL, dbFailOnError
If db.RecordsAffected = 1 Then
MsgBox Me.NameOfComboHere & " has been assigned."
End If
End If
Me.NameOfComboHere.Requery
End Sub
There are a few notes. This assumes that the combobox has a bound column of AccessCardID and that AccessCardID is numeric. It also assumes that you have a reference to Microsoft DAO 3.x Object library. A subform may be the best bet.
EDIT based on Comments
Let us say you have a card id in the guest table, first, add a little code to the Current event for the form:
Me.MyCheckBox = Not IsNull(Me.GuestAccessCard)
This will set the checkbox to false if there is no card id and to true if there is an id.
You will need to change the query for the combobox to:
SELECT AccessCardID
FROM AccessKey
LEFT JOIN Guests
ON AccessKey.AccessCardID = Guest.GuestAccessCard
WHERE Guest.GuestAccessCard Is Null
Then the After Update event would run:
Private Sub NameOfComboHere_AfterUpdate()
If MsgBox("Do you want to assign " & Me.NameOfComboHere & "?", _
vbYesNo) = vbYes Then
Me.GuestAccessCard = Me.NameOfComboHere
Me.MyCheckBox = Not IsNull(Me.GuestAccessCard)
''The data will have to be saved for the
''combo to update with the new data
If Me.Dirty Then Me.Dirty = False
Me.NameOfComboHere.Requery
End If
End Sub
And do not forget to set the GuestAccessCard to Null when the checkbox is unticked and requery the combo.

I may be completely misunderstanding the situation here, but it seems to me that you don't want to have a Boolean field in the table with your cards to indicate if it's checked out -- all you need is a field in your Guests table where you enter the card number. Then you can tell which cards are available with a left join against the card numbers that are in use:
SELECT Cards.CardNumber
FROM Cards LEFT JOIN Guests ON Cards.CardNumber = Guests.CardNumber
WHERE Guests.CardNumber Is Null
This would mean that there's only ever one place where the information is stored (in the Guests table). You could also put a unique index on the CardNumber field in the Guests table (allow Nulls) so you could never assign the same card to two guests.
This may be the way you are doing things, or the way Remou has suggested, but I got too confused by all the convoluted back and forth!

Related

How to record unbound control to a database

I have a form control (address) that uses Dlookup to call info from a table "database" but the form is bound to table "Tracker". The dlookup is based on another control on the same form - "Name" I need the form to record this dlookup control, along with other controls that are bound to "tracker" as new recordto the table "tracker."
My failed attempts:
Using the default value property to assign the recalled data from the dlookup to another text box which would be bound to "tracker" This simply does not work for some reason. Perhaps I am missing something that tells this control "Address" to update upon selecting the correct "name?"
Code:
Private Sub SubmitReferral_Click()
On Error GoTo Err_SubmitReferral_Click
DoCmd.GoToRecord , , acNewRec
Exit_SubmitReferral_Click:
Exit Sub
Err_SubmitReferral_Click:
MsgBox Err.Description
Resume Exit_SubmitReferral_Click
End Sub
I also tried this - to assign the data - but the data from the dlookup in control "Address1" is not transferring/copying to control "Address2"
Private Sub Combo276_OnUpdate()
OnUpdate ([Address2].Value = [Address1].Value)
End Sub
Help or suggestions?
PS - I have tried to Edit per request to be as specific as possible, and to follow proper board etiquette.
Still unsure of your field names, etc., but the following is an example you can modify. Change 'tblEmployee' to 'database'.
I must state that if you are just starting out with developing in Access (or VBA) that you should never use names that are reserved words, or that can be misleading. Your table named 'database' is ok if named 'tblDatabase'.
Option Compare Database
option Explicit
Private Sub cmdInsert_Click()
Dim strSQL As String
Dim i As Integer
Debug.Print "cmdInsert; "
i = MsgBox("Do you want to add 1 row for Employee ID: " & Me.EmpID & " to table 'tracker'?", vbYesNo, "Confirm Add")
If i = vbNo Then
Exit Sub
End If
DoCmd.SetWarnings True
strSQL = "INSERT INTO tracker ( FirstName, LastName, Add1, City, St, Zip ) " & _
"SELECT tblEmployee.FirstName, tblEmployee.LastName, tblEmployee.Add1, tblEmployee.City, tblEmployee.St, tblEmployee.Zip " & _
"FROM tblEmployee " & _
"WHERE (((tblEmployee.EmpID)=" & Me.EmpID & "));"
DoCmd.RunSQL strSQL
End Sub
Thanks for the help - I solved my concern by hiding the fields that contain the dlookup, and putting code behind a button that copies the information to fields that are bound and therefore will record to the table "tracker"

Warning for Dynamic Combobox list

I have a combobox that builds it's list upon first usage. I know that the way I want "NotInList" to behave isn't conventional - I don't want to waste adding the item to a table separate from the needed entry, but I'd like to still warn about an item that hasn't been used yet, so that the user has to think twice before accepting the entry.
Once the user adds the item, it will automatically appear in the list next time because the data source for the combo box is as follows:
SELECT tbl_SP.PROGRAM
FROM tbl_SP
GROUP BY tbl_SP.PROGRAM
HAVING (((tbl_SP.PROGRAM) Is Not Null And (tbl_SP.PROGRAM)<>""));
I tried this:
Private Sub cmbPROGRAM_NotInList(NewData As String, Response As Integer)
If MsgBox("'" & Chr(34) & NewData & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & NewData & "?") = vbYes Then
Response = acDataErrAdded
End If
End Sub
but of course, Access wants the item to actually exist before it will release the error. And...if I set LimitToList to "No" then the user doesn't get a warning.
How can I achieve this behavior?
Ok, I tried this which works fine if the user selects YES, but becomes more complicated when the user selects "NO"
Public Function ReturnsRecords(strSQL As String) As Boolean
Dim d As DAO.Database
Dim arr(1 To 3) As DAO.Recordset
'Dim rs As DAO.Recordset
'assume 3 items in array above
Set d = CurrentDb
Set arr(1) = d.OpenRecordset(strSQL)
' MsgBox "Record Count is " & arr(1).RecordCount
If arr(1).RecordCount > 0 Then
ReturnsRecords = True
Else
ReturnsRecords = False
End If
Set d = Nothing
End Function
Private Sub cmbPROGRAM_BeforeUpdate(Cancel As Integer)
Dim strSQL As String
strSQL = "Select * from LU_PROGRAM where PROGRAM ='" & Me.cmbPROGRAM & "'"
If ReturnsRecords(strSQL) = False Then
If MsgBox("'" & Chr(34) & Me.cmbPROGRAM & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & Me.cmbPROGRAM & "?") = vbNo Then
Cancel = True
' how do I reset this? Me.cmbPROGRAM.Text = Null
End If
End If
End Sub
How do I clear the combobox if the user selects NO? If I select me.undo, that will undo all of the entries, but I just want to clear the combobox.
Incidentally, the form is totally unbound and doesn't accept an entry until the user selects "Save"
First, I'm not quite sure what you wish to achieve ...
Then, educate the users to press Escape to cancel. This is mandatory wisdom when operating an Access application.
For your code to work, you can't change the content of a control in the BeforeUpdate event. So try the AfterUpdate event with either:
Me!cmbPROGRAM.Text = ""
or:
Me!cmbPROGRAM.Value = Null

how to write a script to look for and correct invalid entries in a table

First off I'd like to make perfectly clear that my knowledge of Access and VBA is extremely limited at best. I have an employee database system that due to it's age has been prone to small data corruption issues and controls breaking due to differences between 2003/2007 and 2010. While I've managed to hash out the bulk of the problems, one that has me especially concered is the script we're using to manage access to the database. The system is split between two files, a frontend where users can access the database and a backend file that contains all of the tables.
The issue I have is in the frontend form that handles the logon for the users. The way the access system is set up is the user enters their SSN, then the script finds their SSN in the table and if it exists looks if an access checkbox is checked. If they have access, they're directed to the main menu, if not they get a denied message. What I've found though is for some reason or another, if an entry in the personnel table has an incomplete SSN, the script breaks and anyone can gain access to the database.
There's a query that runs in the frontend that looks at the master personnel table and pulls just the first two columns, SSAN and Access.
The form itself has a visible text box, "Text8", and a hidden Combo Box "Combo4". Combo4 uses the previously mentioned query for the row source (SELECT qryAccess.SSAN FROM qryAccess;), while Text8 is where the user enters their SSN.
Here's the code right now:
Option Compare Database
Private Sub Combo4_AfterUpdate()
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
Private Sub Text8_AfterUpdate()
Me![Combo4] = Me![Text8]
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
Like I said before, as long as every entry for the SSNs is a full 9-digits, this system works. However, if for some reason the entry is not the full 9 like I just found in my database (and no, I have no idea what caused that to happen, there is an input mask in place, 000-00-0000;;_), this system breaks. You could type in "abc" for the SSN and gain access to the database.
How can I write a small script that pre-checks the table for SSN entries that don't fit the 9-digit format that is set, and if it finds them, resets them to an unused number, such as 000000000, 000000001, etc?
Also, if you have any suggestions on how to streamline the existing code, I'd be more than happy to take them.
Add this function to you application
Public Function IsValidSSN(ByVal SSN As String) As Boolean
'Determines if SSN is a valid social security number
'requires SSN to be in either "#########" or "###-##-####" format
IsValidSSN = (SSN Like "###-##-####") Or _
SSN Like ("#########")
End Function
Also change your function to this:
Private Sub Combo4_AfterUpdate()
' Find the record that matches the control.
If IsValidSSN(Me![Combo4]) Then
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
Else
DoCmd.OpenForm "frmDenied"
End IF
End Sub
Private Sub Text8_AfterUpdate()
Me![Combo4] = Me![Text8]
If IsValidSSN(Me![Text8]) Then
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
EDIT
Also why are you using a combobox to enter a SSN? You can use input mask on text box. Also I would highly suggest that you convert your system to some other identification other than SSN because it is easily passable to get past this code to look at the table containing everyones SSN, by holding down shift when opening the application. As for streamlining your code just remove that combobox altogether. If they are typing it into a textbox there is no need to put it into a hidden combobox.
You have a text field, SSAN, and with that input mask the dashes are not included in the stored values. So valid values would be 9 digit strings.
If that is correct, you can use a query to identify any invalid stored values.
SELECT y.SSAN, Len(SSAN) AS LenghtOfSSAN
FROM YourTable AS y
WHERE Len(SSAN)<>9 OR y.SSAN ALike '%[!0-9]%';
That query will return rows where SSAN includes < or > 9 characters, and any values which include characters other than digits.
Note the ALike keyword tells the db engine to expect ANSI wild card characters.  If you prefer Access' * wild card instead, change it to Like '*[!0-9]*'
Once you fix the stored values, add a Validation rule for that SSAN field (Like "#########") to require all values consist of 9 digits.
Since it looks like this became more of a "How do I find the user" than "How do I fix the existing entries", let me throw my hat into the ring.
Unless I completely misunderstand this, the existing (and accepted answer) function is HORRIBLE. You can do this all much more efficiently and with less code. First of all, delete Combo4. No need for it. Then do this:
Private Sub Text8_AfterUpdate()
Dim X as Integer
X = DLookup("Access", "qryAccess", "SSAN = '" & Me!Text8 & "'")
If Nz(X) = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
That's all you need. If the user's SSN was stored incorrectly, he's gonna be denied. 7 digits, 8 digits, doesn't make a difference. Only exact matches get through. That is, assuming 0 = False and 1 = True, which should be the default anyway.

MS Access combo box setting a record with two primary keys

I have a database with 2 primary keys, one for a LINE NUMBER and one for PHASE of construction. The reason for this is that we have projects that may use the same Line Number but must track several Phases of the project entirely seperatly. What I have is a combo box that will drive the record information on a form. This works fine, but now when I have more than one phase it will only bring up the line's first phase and not the other 4 phases. When something other than phas one is picked it results the first phase information.
Is there a way to tie a combo box with 2 fields to select the proper record based on both fields picked?
Or maybe I need to rething the way the form is brought up... Is there a better way to do this?
Code used to select the record:
Sub SetFilter()
Dim LSQL As String
LSQL = "select * from tblLineData_Horizon"
LSQL = LSQL & " where lineno = '" & cboSelected & "'"
Form_frmHorizon_sub.RecordSource = LSQL
End Sub
Private Sub cboSelected_AfterUpdate()
'Call subroutine to set filter based on selected Line Number
SetFilter
End Sub
Private Sub Form_Open(Cancel As Integer)
'Call subroutine to set filter based on selected Line Number
SetFilter
End Sub
A basic idea, but you'll most likely want to tweak the behaviour a bit and have some more checks. When the form loads, you only have the ability to select LineNo. When cbxLineNo has a value in it, it enables cbxPhaseNo for selection and upon selection, it changes the RecordSource of your subform.
Private Sub cbxLineNo_AfterUpdate()
If IsNull(cbxLineNo) Then
cbxPhaseNo.Enabled = False
Else
cbxPhaseNo.Enabled = True
cbxPhaseNo.RowSource = "SELECT PhaseNo FROM tblLineData_Horizon WHERE LineNo = " & cbxLineNo & ";"
End If
End Sub
Private Sub cbxPhaseNo_AfterUpdate()
If IsNull(cbxPhaseNo) = False And IsNull(cbxLineNo) = False Then
tblLineData_Horizon_sub.Form.RecordSource = "SELECT * FROM tblLineData_Horizon WHERE LineNo = " & cbxLineNo & " AND PhaseNo = " & cbxPhaseNo & ";"
End If
End Sub
Private Sub Form_Load()
cbxLineNo.Enabled = True
cbxPhaseNo.Enabled = False
cbxLineNo.RowSource = "SELECT LineNo FROM tblLineData_Horizon GROUP BY LineNo;"
End Sub
You question is a little unclear, but you can create a combobox with more than one column, then your select statement would be:
where lineno = '" & cboSelected.Column(0) & "' And otherfield='"& cboSelected.Column(1)&"'"
Go to the query behind your combobox by clicking into its RowSource property and clicking the Build button (...). Once you've added the columns you need, bring up the Properties for the query and set Unique Values to Yes, so that it doesn't repeat the combinations of the fields.
You will also need to change other properties of the combobox: 'Column Count' and 'Column Widths'.

Runtime query does not work.Why?

I have a Problem with my codes and it made me confuse.this is my scenario:
in my access Project I have a Form and subform that work together.I wanted to enhace my performance . I deceided to load my form and subforms in Runtime(from this article) .I put my query on my form code, in Form_load event like this:
Private Sub Form_load()
Me.RecordSource = "SELECT DISTINCTROW tb_bauteile.* " & _
"FROM tb_bauteile LEFT JOIN FehlerCodes_akt_Liste ON tb_bauteile.CDT = FehlerCodes_akt_Liste.CDT " & _
"WHERE (((FehlerCodes_akt_Liste.Steuergerät)='MEDC17'))" & _
"ORDER BY FehlerCodes_akt_Liste.Fehlerpfad;"
End Sub
but another problem occured with another controls in my form.when i click another control .this function should be run:
Private Sub subPfadFilter(Kombifeld As Variant, Obd As String)
Dim strKrit, strAuswahl, strSg As String
If (IsNull(Me.CDT) Or (Me.CDT = "")) Then
strAuswahl = "*"
Else
strAuswahl = Me.CDT
blnFiltOn = True
End If
.....
but it doesn't work and say me method or dataobjectt not found( without this if statement works the function works fine .the problem come from CDT ) if I put the query in Datasource in my form property that works properly
I cant understand the relation between these two things(putting the query on datasource of form property then working the if statement (CDT) good but when i put the query in Form load that does not work ) ,would you please help me if posible?have you any idee?
thank you so much for your helps
When using the "Me" reference, you need to ensure the code is behind the present form, you've mentioned that the Form_Load code is on there, but is the "subPfadFilter" somewhere else?
If so then it needs to either be moved on to this form, or change your reference to the forms name instead of "Me".
If it is on the form then the error seems to be complaining about the CDT item, you will need to confirm that this is the name of either a text field or a control on this form.
If it is then you can try inserting:
Me.Requery
After your SQL statement, this may wake up the forms reference to the object.
This bit is not essential but to avoid carrying out two tests on CDT and streamlining your code slightly I would amend to this:
If Me.CDT & "" = "" Then
strAuswahl = "*"
Else
strAuswahl = Me.CDT
blnFiltOn = True
End If
This captures both Is Null or "" in one shot.
UPDATE:
For an unbound form, you need to set your form's controls via VB as well as the forms recordsource e.g:
Private Sub Form_load()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("SELECT DISTINCTROW b.* " & _
"FROM tb_bauteile As b LEFT JOIN FehlerCodes_akt_Liste As f " & _
"ON b.CDT = f.CDT " & _
"WHERE f.Steuergerät = 'MEDC17' " & _
"ORDER BY f.Fehlerpfad;")
rs.MoveFirst
Me.CDT = rs!CDT
'Any other fields go here
rs.Close
Set rs = Nothing
End Sub
However if you are returning more than one record at a time then you will either need to stick with a bound form or perhaps use a listbox to display your information. Unbound forms do not use the Forms "Recordset" property.
Note: I have also 'Aliased' the table names in your SQL statement, this is a good practice to get into : )