MSAccess dynamic search form with multiple searchable fields and NULL values - forms

I have a form in my MSAccess application that searches the master database across 4 fields. You can fill in as little into 1 field or as much into all 4 fields or anywhere in between that you desire.
The database fields to be searched are:
rmanbr - Integer
custNbr - Integer
customername - Text
invcmnbr - Text (as it will store either invoice numbers (######) or credit memo numbers (CM-####)
The form has 4 fields in which to sort by respective of the above:
SrchRMANbr
SrchCustNbr
SrchCoName
SrchInvCMNbr
I have a query that selects all of the data to be displayed. The 4 fields to be filtered are filled with Like "*" & [forms]![RMA Search]![FieldName] & "*" into the Criteria section of the Query Builder for that specific query
The rmanbr and customername fields in the database will never be NULL, they're not allowed to be. But, the invcmnbr and custnbr can be and frequently are NULL with no values.
So, my search form is the 4 Srch fields listed above where users can enter in the stuff they want to filter by. There is a listbox that is designed to start filtering the results based on the "On Change" of the text boxes that the user will use to filter results. The user then selects the record and goes on his merry way.
However, the ListBox is filtering out all NULL Values from the two fields that can be NULL, whether or not the corresponding Srch box is blank, so the rows with NULL either in the custnbr or invcmnbr fields is not showing up in the listbox.
I've tried stuffing a Is Null into the "Or" Criteria of the query I'm using to populate the listbox. I tried it in the second line of the Query Builder Criteria section "Is Null" and this showed all the rows if they had NULL values even if I entered in a number into SrchRMANbr field. Ideally entering in an RMANbr would filter by RMANbr whether or not NULL values existed, since this is a unique value (there can only be 1 of any RMANbr in the master table). If I put after the Like "*" & [forms]![RMA Search]![FieldName] & "*" in the criteria (on the same line) Or Is Null it would get me closer, but any search into the SrchCustNbr or SrchInvCMNbr fields would produce the filtered result as well as all the NULL values for that field.
So, in short, I require a way to:
1) Show all of the values, NULL or not, in the listbox before a user starts to enter data in any field.
2) Filter away the NULL values when a user starts to enter data into the SrchCustNbr or SrchInvCMNbr field.
3) Keep the NULL Values up but filter by RMA Nbr correctly when the user starts to enter an number into the SrchRMANbr (as this is the master record, this is as specific as it can get)
I hope I'm conveying the issue correctly. Let me know if you need any additional information to assist me in solving my issue.

Using the solution posted here: MS Access: Ignoring query criteria if blank and pointed out by Andre
I've simply added Or ([forms]![RMA Search]![SrchCustNbr] Is Null) after the original Like "*" & [forms]![RMA Search]![FieldName] & "*" in both the CustNbr and InvCMNbr fields and this has worked.

As you are finding out, putting forms! expression in queries can get really messy real fast.
Even worse, is now that the query is now "married" and attached to that ONE form. Often, I have a nice query that I could use MANY times for different reports, and often even that same query could be used for reports...but then someone comes along and puts in a expression that means the query is ONLY good when that form is opened.
Worse, is very hard to control things like having 5 combo boxes, but the user only selects restrictions in 3 of the combo boxes...and wants the other 2 to be ignore.
I could probably write another 10 or pages as to why putting forms expressions in queries is bad (besides...it makes the queries real ugly, and hard to read. and, the sql then is not standard anymore (it will not work with server based systems either).
So, the solution is to simply to take the values from the form, and build your own where clause in code. That way, you simply design the reports (or forms), and attached them to the query, BUT NO FORMS! conditions are placed in the query.
To "send" the conditions to the report (or form), you simply use the "where" clause. This is exactly why ms-access has this feature…and it solves a zillion problems…and will reduce your development costs by a substantial amount.
Take a look at the following screen shots to see what I mean:
http://www.kallal.ca/ridesrpt/ridesrpt.html
The code to make those above screens work and launch the report with the selected restrictions when you hit the "print" button is easy:
dim strWhere as string
' select sales rep combo
if isnull(cboSalesRep) = false then
strWhere = "SalesRep = " & cboSalesRep & ""
end if
' select what City for the report
if isnull(cboCity) = false then
if strWhere <> "" then
strWhere = strWhere " and "
endif
strWhere = strWhere & "City = " & cobCity & ""
end if
Note how the 2nd combo test is setup. You can add as "many" more conditions you want. Lets say we have a check box to only include Special Customers. We can add to our very nice prompt screen a check box to
[x] Show Only Special customers
The code we add would be:
if chkSpeicalOnly = True then
if strWhere <> "" then
strWhere = strWhere " and "
endif
strWhere = strWhere & "SpecialCust = true"
end if
For sure, each combo and control we add to the nice report screen takes a bit of code, but no more messy then the query builder..and this way, each query is nice and clean, and free of a bunch of HIGHLY un-maintainable forms! expressions.
Further, it means you can re-use the same query for different reports, and have no worries about some form that is supposed to be open. So, a tiny bit more code eliminates the messy query problem.. For me, this is very worth while trade.

Related

How do I search forms in Access using values from another table that is being referenced?

The management staff in my department has been asked to record any and all errors committed by our team. I created a database to store them and a simple form for the management team to use to record each error. Several fields are referencing other tables such as Staff, issue category, root cause, etc...
We need to be able to search the forms for specific records to either update or review, and I have found the best way for us to search is by filtering the forms based on the individual who committed the error. Here is the code that I am using for the search button:
Private Sub SearchRecord_Click()
Dim Search As String
Search = InputBox("Please enter who committed the error", "Name", ErrorMadeBy)
If Search = "" Then Exit Sub
Me.Filter = "ErrorMadeBy = """" & Search & """
Me.FilterOn = True
End Sub
The filter works great, but instead of filling out the name, you have to use the ID number in the Staff table when filling out the Input Box. I'd like to be able to input the name (or part of the name) instead of having to have everyone memorize the ID numbers from the staff table.
What I do in these cases?
Fire up the query builder - left join in those extra tables (with the text parts in place of the id).
So be it a part number, quote number for a project etc? Just left join in those tables in the query builder and save that query.
Now, your search box and code can be somthing like:
dim rst as DAO.RecordSet
strSQL = "Select * from MyCoolQuery where PartName like '" & txtPartName & "*'"
set rst = currentdb.OpenRecordSet(strSQL)
if rst.EOF = false then
me.RecordSet.FindFirst "PartID = " & rst!PartID
end if
In fact, you can even often left join in those extra tables right into the current form, and even use ctrl-f to search if the said text boxes are place on the given form. However, I tend to separate out the search process from the actual form. So I might build a search form, say like this:
So in above, they can search say by a Hotel name, or project name or whatever. Becuase the one query has the text parts, then they can be searched. But I put the query results into a grid and each row of course has the PK ID, and thus a search could result in 10 matches, they are now free to click on any row - and i jump to the form to display the one records.
eg: the row click button does this:
docmd.OpenForm "frmTourBooking",,,"ID = " & me!ID
So, this makes for a great work flow. Users search, see, pick and then jump to the form with the one record, and then close and return back to search form - and often it has the several "hits" from that search that you want to work on anyway.

Microsoft Access - Creating a form which looks up data between 2 dates

For my College assignment, I have to create a database in Access, I have done 99% of my database, apart from this section which I'm stuck on.
In my DB, I have a tickets table, which contains records on order information and a field containing a date. For my assignment, I have to create a Form which reads from a Query.
For example, in my Form i have already created i have 2 Combo boxes with the dates already pulled from the Query. I need to be able to drop down one of the boxes and input 1 date, and then drop down the other box and select a different date, press a button and it generate me a Report.
The part I am asking for help on is the expression which is used to look up the data inside the Query. I tried using this expression, which Access said was too complicated.
[Forms]![frmOrdersBetweenTwoDates]![Combo33] And [Forms]![frmOrdersBetweenTwoDates]![Combo36]
My full SQL query is:
SELECT tblTickets.CustomerID, tblCustomers.FullName, tblCustomers.AddressLine1, tblTickets.OrderNumber, tblTickets.OrderDate
FROM tblCustomers INNER JOIN tblTickets ON tblCustomers.[CustomerID] = tblTickets.[CustomerID]
WHERE ((("WHERE [OrderDate]") Between [Forms]![frmOrdersBetweenTwoDates]![Combo52] And [Forms]![frmOrdersBetweenTwoDates]![Combo54]));
My expression/query now returns the report, but there is no data inside the report. How could i fix this?
Cheers.
Should post the complete query statement. Expect the filter clause should be like:
WHERE [date fieldname] BETWEEN [Forms]![frmOrdersBetweenTwoDates]![Combo33] AND [Forms]![frmOrdersBetweenTwoDates]![Combo36]
However, I don't use dynamic parameterized queries. I prefer to use the WHERE argument of OpenReport (same for OpenForm), in VBA:
DoCmd.OpenReport "report name", , , "[date fieldname] BETWEEN #" & Me.Combo33 & "# AND #" & Me.Combo36 & "#"

Access 2010 Form Button Problems

I am currently at a loss for what to do in my current project. I am creating a form that will pull up a customer’s data. It is possible the customer could have more than record, and I have three different distinct fields to help narrow to that exact customer. We have an ID field which would be primary key, their SSN which only relates to them, and their account # which also only relates to them. I am curious if there is a way for the form to not be populated when I start it, and either be able to type in a text box one of these 3 and have them linked to a query that will search for that record and fill the form with the data, or have it pull up a parameter box(can do, but cant get the data to populate in form view) I am not having any luck with using the command buttons, either they don’t work the way I want them to, or the data gets pulled up in a datasheet, instead of my form.
I can manually filter on the ID numbers to find the record, but I’d rather make this user friendly for future users.
Also the form currently houses 95 fields of data, but they fit very comfortably in the form.
Access 2010
You can certainly have the form not populated. Create your three textboxes and a "go" button.
The code for the go button would be something like:
If Not IsNull(Me.txtID) Then
sWhere = sWhere & " Or ID=" & Me.txtID
End If
If Not IsNull(Me.txtSSN) Then
''If SSN is text, you need quotes
sWhere = sWhere & " Or SSN='" & Me.txtSSN & "'"
End If
If Not IsNull(Me.txtAccountNo) Then
sWhere = sWhere & " Or AccountNo=" & Me.txtAccountNo
End If
sWhere = "WHERE 1=1 " & sWhere
sSQL = "SELECT Each, Field, Name FROM TableName " & sWhere
Me.RecordSource = sSQL
The above is typed, not tested, and is only one approach. You could also use comboboxes built with the wizard to select a customer on your form, you could have a previous form where you fill in a customer and open your form from that, you could just filter your form based on what is filled in and so on.
As far as I know, there are rules about storing SSNs, so you will need to be careful.

Apply a Report filter in code

My particular, specific issue is probably too localized, but the general question I'm about to ask is something I'm sure others will ask and have wondered:
General question: In Sql Server Reporting Services, is it possible to apply a filter to a report in code? If not, is it possible to use branching in the report filter based on the value of a variable, and can you point me to documentation or explain how to do it.
My specific example follows, to expand on what I mean by the above, in case I worded it badly:
I'm learning SSRS and the docs and Google are coming up short.
The desired effect is that we have a report based on an incident tracking system. In this system, we have various teams that can track incidents: IT Ops, Development, Security, etc. Each of these teams have team members assigned.
We have a base report that displays ALL incidents.
We have added a boolean parameter named "LimitByTeam", which produces a CheckBox on the report as you'd expect.
We have added a String parameter that accepts multiple values. The allowed values come from a data set that lists the teams. This has added the expected drop-down list to the report, allowing users to select one or more teams.
We added a dataset that contains team and team member.
If the CheckBox is NOT selected, we want to display all incidents. (The default)
If it IS selected, we want to have the report to filter based on the login ID of the person who created the incident ticket.
Were I to do this in SQL, I'd do it as
Select
(ticket fields)
From
Table
WHERE TicketCreator IN (
Select LoginId FROM TeamMembersTable
WHERE TeamName in ('IT Ops', 'Developers'))
In SQL, or in VB, etc, this would be simple.
In SSRS I'm not figuring out quite how to do this. I've gotten as far as figuring out that I can use Custom Code to do more complex logic using VB (and it appears to be VB.NET. HOORAY! Familiar territory)
So I've added custom code and verified that I can read the value of the report parameter, but I can't figure out for the life of me how to apply a filter if the parameter value is True. Here's what I've got.
Public Sub ApplyTeamFilter()
' Report.Parameters("LimitByTeam") is a
' boolean report parameter that I'm able to access
' so I've got the IF statement worked out
If Report.Parameters("LimitByTeam").Value = True Then
' Pseudo-code - I'm looking for something like Report.Filters.Add(filterstatement)
' Alternatively a way to change this to a function to return a list of items from
' the Team MembersTable table and use it in a custom expression.
End If
End Sub
The problem is that I can't seem to find a Filters property on the Report object, or any method that lets me find it. Since I couldn't find it there, I expanded my search to everything in this section of the MSDN library and can't find it, or anything even remotely resembling a way to do what I'm attempting.
I'm also trying to do something like this because I think I see a way to use this function:
Public Function IsLoginIdInTeam(ByVal LoginId as String, byVal Team As String) As Boolean
' Report.Parameters("LimitByTeam") is a
' boolean report parameter that I'm able to access
' so I've got the IF statement worked out
If Report.Parameters("LimitByTeam").Value = False Then
Return True ' Default
Else
' Access the TeamMembers table and look for a match
' Something like
' Convert.ToBoolean(Report.DataSets!TeamMembers.Compute(Count, "TeamName = '" & Team & "' AND LoginId = '" & LoginId & "'")
End If
End Function
But I can't figure out how to access the Data Sets in the report, either, much less the syntax for interacting with them. The pseudocode works with a System.Data.DataTable, but I suspect SSRS DataSets are a different beast.
Am I missing something blindingly obvious? Should I be giving up on filtering this way in the report, and try another track, like changing the original query in the DataSet?
I'm not a huge fan of boolean parameters in SSRS (or BIT in SQL for that matter.) You can't write things like
WHERE #MyBool OR #MyOtherBool
It needs to be
WHERE #MyBool = 1 or #MyOtherBool = 1
So if I have an SSRS report with a boolean called MyBoolParam and a multivalue text parameter called MyMultiSelectTextParam , a SQL query like this will work:
SELECT
MyField,
MyOtherField
FROM
MyTable t
WHERE
#MyBoolParam = 1
OR
t.MyField IN ( #MyMultiSelectTextParam)
(My preferred alternative to boolean parameters is actually a string with possible values, but it would be handled in the query in the same way.)
If you can't easily change your SQL query (such as using a third party SP) then you can also accomplish the same thing by adding a filter to the SSRS DataSet. Right click on the DataSet in the Report Data pane and look at the Dataset Properties. The Filters pane will let you add criteria that are evaluated for each row. I haven't used these as much with multivalue parameters, but the IN Operator should work for that.

DB2 - handling columns defined as null

Let's say you have three textboxes that you can use to search for data. Each textbox will correspond to a column on the DB2 table. The search string you enter will be inserted into the where clause. For example, you have First-Name, Last-Name, and Phone Number. If you don't enter data into a particular textbox, I default its value in the where clause to '_', the wildcard character to select everything. Also, lets say Phone Number is defined as NULL on the table.
Cursor1 will be used if the user has entered a Phone number to search for. So the where clause will look something like this:
Where FIRST_NAME like :firstname AND
LAST_NAME like :lastname AND
PHONE_NBR like :number
This works when data is entered for phone number. But if a search is done for First Name only, the cursor returns partial or no results because the :number host variable will be populated with the "_' wildcard. PHONE_NBR like '_' will only return the rows that have a real value. If there is a null for PHONE_NBR on a row that matches the First Name you searched for, that row won't show up. So I created a second cursor.
Cursor2 will be used if the user HAS NOT entered a Phone number to search for. The Where clause looks something like this.
Where FIRST_NAME like :firstname AND
LAST_NAME like :lastname AND
(PHONE_NBR like :number OR
PHONE_NBR IS NULL)
So again, if a search was done for a first name only, and some values in PHONE_NBR have data, some are null, EVERYTHING that matches the first name that is searched for will show in the results - which is good. For the rows with values in PHONE_NBR, PHONE_NBR like '_' will get those. For the rows with null in PHONE_NBR, PHONE_NBR IS NULL will get those.
This is a minor yet necessary difference. Because of this minor difference, I would like to combine these two cursors into one. How can that be done to achieve the same results?
Ian, i think the difference is if the user supplies a number he doesn't want to return rows with a null. using cursor 2 all the time would return rows with null along with matching numbers.
You could try a CASE statement based on :number...though i'm not sure if you can use a CASE with "is null" syntax. i know you could if you were just checking for different values (equal to, less than, etc).
The way I'd recommend handling this is by building the query to supply conditions only on the columns where the user enters data. That is:
If the user enters something in the First_Name text box, you have a condition such as:
FIRST_NAME LIKE '...'
If the user enters something in the Last_Name text box, you have a condition such as:
LAST_NAME LIKE '...'
If the user enters something in the Phone_Nbr text box, you have a condition such as:
PHONE_NBR LIKE '...'
In each case, the 3 dots represent a string derived from the information typed into the text box, and the function that does that conversion is fully aware of quoting (to avoid SQL injection).
If the user types in two or three of the text boxes, the independent conditions are joined by an AND. If the user types nothing, you can generate a tautology such as 1 = 1 as the condition.
You then append that condition to the WHERE clause of the SQL statement, and then arrange to execute it.
This is the technique made available by the CONSTRUCT statement in IBM Informix 4GL; it has been available there since 1986. It allows for conditions other than just LIKE, such as equals, less than, greater than or equal to, ranges, or even a list of alternatives (for an IN ('val1', 'val2', ...) condition), and it can be used for all data types.