I am working on a C# desktop application. I want to create a search functionality. Now the problem is that i am using around 8 textboxes. Different permutations of textboxes could be populated and the resulting 'sql where' condition should only include those textboxes values which are not null. Now one pathetic way is to use a zillion 'if and else' which obviously is laborious. Any other way to do this?
You need just one query with filled WHERE to use all parameters like this
select ...
from ...
WHERE
(firstNameColumn=:firstNameParam or :firstNameParam is null)
AND (lastNameColumn=:lastNameParam or :lastNameParam is null)
AND (...)
I would like to make a point of first checking is the paramtere null, then use it to compare with column values.
Since you are generating query in C#, try old-Chinese approach from Ming period of using default condition where 1=1 just to avoid checking did you already had first condition :)
string query = "select ... from ... join ... on ... where 1=1";
//suposedly you have value of one search box in variable called "item_name"
if(string.IsNullOrWhiteSpace(item_name) == false)
{
query += " and Order_Line.Name ='" + item_name + "'";
}
and so on for other fields.
What you are trying to do in order to avoid ifs is not really a good approach. Look at this:
string query = " select ... where Order_Line.Name = '" + item_name + "'";
What will be the resulting string if item_name is actually null?
EDIT: the resulting query would be
where Order_Line.Name = '' or Order_Line.Name is null
which is not what you want. You want every row if that search field is empty, menaing it shouldn't have anu effect on search. That's why you need condition to see will you include this column in where clause in the first place.
Related
Access 2013 - Reference an Unbound text box on a Form
I am currently trying to use an unbound text box [Text161] on a Form name [DCM_Gap_Servers] to sort information through a table. I want the query that I created to be able to take the users input from [DCM_Gap_Servers]![Text161] as the field that is being sorted from the table names 'Server'.
This is the SQL I am using right now in the query:
SELECT * FROM Servers WHERE "Forms![DCM_Gap_Servers]![Text161]" IS NULL
** I have already Tried:
"Forms![DCM_Gap_Servers]![Text161]" ; (Forms![DCM_Gap_Servers]![Text161]); Forms.[DCM_Gap_Servers]![Text161]
This will work at any time if I replace the Text Box reference with the actual Field name I am using, but since there are hundreds of combinations of fields, I need the reference to work.
I have looked all over, and I can't seem to find the correct answer. I am willing to do it in VBA if needed, whatever it takes to get the filtering done correctly.
Thank You.
It is:
SELECT * FROM Servers WHERE Forms.[DCM_Gap_Servers].[Text161] IS NULL
but that will just select all records whenever your textbox is Null.
So it rather is:
SELECT * FROM Servers WHERE SomeField = Forms.[DCM_Gap_Servers].[Text161]
To use the form value as a field name, you must use concatenated SQL:
strSQL = "SELECT * FROM Servers WHERE " & Forms![DCM_Gap_Servers]![Text161].Value & " IS NULL"
This you might pass to the SQL property of an existing query object:
MyQueryDef.SQL = strSQL
Or:
Constant SQL As String = "SELECT * FROM Servers WHERE {0} IS NULL"
FieldName = Forms![DCM_Gap_Servers]![Text161].Value
MyQueryDef.SQL = Replace(strSQL, "{0}", FieldName)
Of course, take care the the field name isn't a zero length string.
I am trying to update a field in a table using an SQL update query where there is a like statement referencing a value in another table. They syntax unfortunately is not working. Below is my code. In short, I am trying to put a '1' in the field 'Query07ParolaChiave' in the table 'tblSearchEngine01' when the value located in table 'tblsearchengine07' is present in the field 'tblMasterListOfEventsNotes' located in the table 'tblSearchEngine01'. I think my code is almost complete but there is a syntax issue which i cant find.
st_sql = "UPDATE tblSearchEngine01, tblSearchEngine07 SET tblSearchEngine01.Query07ParolaChiaveSelect = '1' WHERE ((([tblSearchEngine01].[tblMasterListOfEventsNotes]) Like " * " & [tblsearchengine07].[ParolaChiave] & " * "))"
Application.DoCmd.RunSQL (st_sql)
I suggest you 2 solutions :
This one is using EXISTS functions, and will check for each row in tblSearchEngine01 if there is a matching value in tblsearchengine07
UPDATE
tblSearchEngine01
SET
tblSearchEngine01.Query07ParolaChiaveSelect = '1'
WHERE
EXISTS (SELECT 1
FROM tblsearchengine07
WHERE [tblSearchEngine01].[tblMasterListOfEventsNotes] Like '*' & [tblsearchengine07].[ParolaChiave] & '*')
This one is more performant because it uses JOIN
UPDATE
tblSearchEngine01
INNER JOIN tblsearchengine07
ON [tblSearchEngine01].[tblMasterListOfEventsNotes] Like '*' & [tblsearchengine07].[ParolaChiave] & '*'
SET
tblSearchEngine01.Query07ParolaChiaveSelect = '1'
I read something like in ADO/VBA, you have to use % instead of * as the wildcard.
You can have more information on wildcard and LIKE comparator here
UPDATE
Why the '1' after select in your first solution?
EXISTS (SELECT 1 ... is better for performance because it return only the number 1 instead of fields, anyway EXISTS just stop the excecution after 1 element found.
'Performant' means more consuming in regards to space and memory?
JOIN is more performant in term of time of execution, RDBMS are far better at joining tables than using subquery, in some rare case, it's more interesting to use the 1st solution.
Also, any initial thoughts as to why my original solution (coming straight from an Access Query which works) does not function?
I cannot really know but perhaps it's because of " * ", because you are saying SPACE + * + SPACE + VALUE + SPACE + * + SPACE. For ex : 'John' LIKE ' John '
May be with "*" instead of " * " could solve it...
I have no other track, I'm not Access sql developper, I usually play around Sql server/Oracle/mySql, hope it helped. ;)
Try to change your like this way:
... Like '*" & tblsearchengine07.parolachiave & "*'))"
The like statement go into the WHERE clause.
If you do want to use LIKE without you care about caps letters, then you can use it like this:
LIKE COLUMN_NAME = '%WhatYouLike%'
My suggestion is:
Use a table variable (#Table) with a unique/primary key coming from the table to be updated.
SELECT all the data to be updated (you can add the like statement here) and then INSERT that in the created table variable.
Construct the UPDATE statement with an INNER JOIN to the table variable matching with the unique/primary key.
I know this may take a lot of steps but believe me these are more efficient than using a black list approach.
I have a db in Access and I'm trying to get a textbox to run my query and pass an other bounded textbox's value in as the criteria in DLookUp. I have the query running in design view and when I enter the criteria directly it returns the correct results. When I open the report it gives me the sum of all the possible rows. In other words it doesn't filter the rows.
I haven't used Access in about twelve years, thankfully, and everything I've done up to this point has been tutorial/example patchwork, but here it is...
SQL Query:
SELECT Sum(IIf(Attended=-1,1,0)) AS attendance
FROM Students_Classes_Attendance
WHERE (((CStr([Students_Classes_Attendance].[Class_Id]))=[classId]));
DLookUp as Control Source:
=DLookUp("[Total Attendance by Class]![attendance]",
"[Total Attendance by Class]",
"[Class_Id] =" & [Class_Id])
I'm lost at the moment. I'm guessing that the value isn't there before the query fires and since the criteria is an optional parameter that it's being passed null, but I would hope you'd get an error from that. Not that #Error is very meaningful anyway.
Does anyone know for certain the problem and the best way to correct it? Thanks.
Edit:
I did the changes recommended in the answer so now my DLookUp looks like...
=DLookUp("[attendance]",
"[Total Attendance by Class]",
"[Class_Id] =" & [Class_Id])
...still returns the total for all rows. Removing the criteria completely makes no difference either, which returns me to thinking it has something to do with the bound textbox not having a value.
DLookup uses the following syntax:
Syntax for numerical values:
DLookup("FieldName" , "TableName" , "Criteria = n")
Syntax for strings: (note the single apostrophe before and after the string value)
DLookup("FieldName" , "TableName" , "Criteria= 'string'")
Syntax for dates: (note the # before and after the date value)
DLookup("FieldName" , "TableName" , "Criteria= #date#")
I believe you just need to remove the table name from the first parameter. Try this:
=DLookUp("[attendance]", "[Total Attendance by Class]", "[Class_Id] = " & [Class_Id])
Keep in mind that if Class_Id is a Text Field, you need to surround it by single quotes:
=DLookUp("[attendance]", "[Total Attendance by Class]", "[Class_Id] = '" & [Class_Id] & "'")
I want to create a report by using BIRT. I have 5 SQL criterias as the parameter for the report. Usually when I have 3 criterias, I am using nested if-else for the WHERE statement with javascript.
Since right now I have more criteria it becomes more difficult to write the code and also check the possibilities, especially for debug purposes.
For example the criteria for table employee, having these 5 criterias : age, city, department, title and education. All criteria will be dynamic, you can leave it blank to show all contents.
Do anyone know the alternative of this method?
There is a magical way to handle this without any script, which makes reports much easier to maintain! We can use this kind of SQL query:
SELECT *
FROM mytable
WHERE (?='' OR city=? )
AND (?=-1 OR age>? )
AND (?='' OR department=? )
AND (?='' OR title=? )
So each criteria has two dataset parameters, with a "OR" clause allowing to ignore a criteria when the parameter gets a specific value, an empty value or a null value as you like. All those "OR" clauses are evaluated with a constant value, therefore performances of queries can't be affected.
In this example we should have 4 report parameters, 8 dataset parameters (each report parameter is bound to 2 dataset parameters) and 0 script. See a live example of a report using this approach here.
If there are many more criteria i would recommend to use a stored procedure, hence we can do the same with just one dataset parameter per criteria.
Integer parameter handling
If we need to handle a "all" value for an integer column such age: we can declare report parameter "age" as a String type and dataset parameters "age" as an integer. Then, in parameters tab of the dataset use a value expression instead of a "linked to report parameters". For example if we like a robust input which handles both "all" "null" and empty values here is the expression to enter:
(params["age"].value=="all" || params["age"].value=="" || params["age"].value==null)?-1:params["age"].value
The sample report can be downloaded here (v 4.3.1)
Depending on the report requirements and audiance you may find this helpful.
Use text box paramaters and make the defualt value % (which is a wild card)
SELECT *
FROM mytable
WHERE city like ?
AND age like ?
AND department like ?
AND title like ?
This also allows your users to search for partial names. if the value in the city text box is %ville% it would return all the cities with "ville" anyplace in the city name.
If report parameters to be included in SQL-WHERE clause would be named according to some naming convention, for instance query_employee_[table column name], you could write Java-Script code in a generic way, so that you will not have to change it when new reporters being added.
for each param in params {
if param.name starts with query_employee_ {
where_clause += " and " + param.name.substring(after query_employee) + " == '" + param.value + "'";
}
}
You will have to check type of a parameter to make a decision whether you have to quote the parameter value.
The event handler could look as follows (implemented in Java, but it should be possible to port it to JavaScript, if you really need it to be in JavaScript):
public class WhereConditionEventHandler extends DataSetEventAdapter {
#Override
public void beforeOpen(IDataSetInstance dataSet,
IReportContext reportContext) throws ScriptException {
super.beforeOpen(dataSet, reportContext);
String whereClause = " where 1 = 1 ";
SlotHandle prms = reportContext.getDesignHandle().getParameters();
for (int i = 0; i < prms.getCount(); i++) {
if (prms.get(i) instanceof ScalarParameterHandle) {
ScalarParameterHandle prm = (ScalarParameterHandle) prms.get(i);
int n = prm.getName().indexOf("sql_customer_");
if (n > -1) {
String prmValue = "" + reportContext.getParameterValue(prm.getName());
if (DesignChoiceConstants.PARAM_TYPE_STRING.equals(prm.getDataType())) {
prmValue = "'" + prmValue + "'";
}
whereClause += " and " + prm.getName().substring("sql_customer_".length()) + " = " + prmValue;
}
}
}
System.out.println("sql: " + whereClause);
dataSet.setQueryText(dataSet.getQueryText() + whereClause);
}
}
By the way, you can pass in parameters that are not registered as report parameters in the BIRT report design. BIRT will nevertheless put them into "params" array.
I have a problem very similar to this one, but I just can't seem to solve it!
In MS Access (2003), I want to search a table based on entries in a number of fields, some of which may be empty.
I have:
text fields
date fields
integer fields, and
a memo field (but we can probably not bother searching this one if it is difficult).
They map onto a table exactly.
I am trying to create a query that will return matching rows when data is entered into one or more of these fields, but some fields can be left blank. How the heck do I do this?
A query like the one on the linked question works for text fields, but what do I do about the number fields, date fields (and possibly even the memo field)?
To give a clear example, the following code block works for TextField1, but not NumberField1:
PARAMETERS [Forms]![SearchForm]![FilterTextField1] Text ( 255 ), [Forms]![SearchForm]![FilterNumberField1] Text ( 255 );
SELECT Table1.[TextField1], Table1.[NumberField1], Table1.[TextField2], Table1.[TextField3], Table1.[DateField1], Table1.[DateField2], Table1.[DateField3]
FROM Table1
WHERE (Len([Forms]![SearchForm]![FilterTextField1] & '')=0 OR Table1.[TextField1] Like '*' & [Forms]![SearchForm]![FilterTextField1] & '*') AND (Len([Forms]![SearchForm]![FilterNumberField1] & '')=0 OR Table1.[NumberField1] Like '*' & [Forms]![SearchForm]![FilterNumberField1] & '*');
I do hope you can help. I'm sure I'm missing something really obvious, but for some reason my brain feels like it is leaking out of my ears at the moment.
Thank you!
If you need it, this is the basic design of the relevant entities:
Table1
SomePrimaryKeyWeDontCareAboutRightNow
TextField1
TextField2
TextField3
NumberField1
DateField1
DateField2
DateField3
MemoField1
SearchForm
FilterTextField1
FilterTextField2
FilterTextField3
FilterNumberField1
FilterDateField1
FilterDateField2
FilterDateField3
FilterMemoField1
You can check fo null values or cast to string
You could certainly spend a great deal of time crafting a huge and very hard to debug SQL query for this, or just jump into VBA and write some code to construct just the SQL you need.
VBA is there just for these kinds of scenario, where something is either impossible or becoming too complex to do otherwise.
With VBA, you can use an initial SELECT query that collect all the data, and then construct a WHERE clause based on the content of your search form to filter it.
For instance, I have a form like this, that allows the user to enter any criteria to filter a list of prices:
Some code to implement this could look like:
' Call this whenever the use click the Apply button '
Private Sub btApply_Click()
' Construct the filter '
Dim filter As String
If Not IsBlank(cbSupplierID) Then
If Not IsBlank(filter) Then filter = filter & " AND "
filter = filter & "(SupplierID=" & cbSupplierID & ")"
End If
If Not IsBlank(txtPartNumber) Then
If Not IsBlank(filter) Then filter = filter & " AND "
filter = filter & "(PartNumber LIKE '*" & txtPartNumber & "*')"
End If
If Not ckShowLocked Then
If Not IsBlank(filter) Then filter = filter & " AND "
filter = filter & "(NOT PriceLocked)"
End If
' ... code snipped, you get the jest ... '
' Now re-construct the SQL query '
Dim sql As String
sql = "SELECT * FROM Price"
If Not IsBlank(filter) Then
sql = sql & " WHERE " & filter
End If
SubForm.Form.RecordSource = sql
End Sub
It may seem like a lot of code, but each block only does one thing, and it's a lot easier to debug and maintain than cramming everything into a query.