MS Access Dropdowns to filter through table - vba

i have a big table, and have created a form that filters through that data.
However, at the moment, these filters do not work.
There are dropdown filters which correspond to columns and the idea is to choose a value from a specific column and get the rows with only the choosen value, also to filter few columns at once like that if neccessary - each box has mostly the same code, just the change of names.
Here is an example of one box code :
Private Sub klk_AfterUpdate()
Dim klkxas As String
klkxas = "Select * from daca where ([wdwqd] = '" & Me.cboLiefName & "') and ([sdcxsadc] = '" & Me.cboSRat & "') and ([Verantwortlicher] = '" & Me.cboVerant & "') and ([cxsacx] = '" & Me.cboLiefKat & "') and ([qxqxsa] = '" & Me.cboliefart & "') and ([sxsa] = '" & Me.cboLand & "') and ([sdxs] = '" & Me.cboAudErg & "')"
Me.Form.RecordSource = klkxas
Me.Form.Requery
End Sub
Can someone help me on how to change the code so it works?
Thanks in advance

If I were to guess, your issue is that even selecting one or more but not all comboboxes (i.e., leaving some comboboxes blank) results in no returned rows. Per your attempted query, this is not an error but valid result of SQL logic. Your users would need to correctly select values in all seven comboboxes to get any rows back.
One solution of this dynamic filtering problem is to use NZ (or IIF) to match each field to itself for non-selected comboboxes. Also, use a saved SQL query that points to form controls without any concatenation of VBA values and punctuation of quotes.
Below will return values if any one or all controls are selected. But do note after combobox selection, only rows with non-NULL across all fields will be returned. Be sure to adjust myForm to actual form name in query:
SQL (save as separate query and as recordsource to form)
SELECT *
FROM Lieferant
WHERE [Bezeichner] = NZ(Forms!myForm!cboLiefName, [Bezeichner])
AND [S_Rating] = NZ(Forms!myForm!cboSRat, [S_Rating])
AND [Verantwortlicher] = NZ(Forms!myForm!cboVerant, [Verantwortlicher])
AND [Lieferantenkategorie] = NZ(Forms!myForm!cboLiefKat, [Lieferantenkategorie])
AND [Lieferantenart] = NZ(Forms!myForm!cboliefart, [Lieferantenart])
AND [Land] = NZ(Forms!myForm!cboLand, [Land])
AND [Audit_Ergebnis] = NZ(Forms!myForm!cboAudErg, [Audit_Ergebnis])
VBA (single line!)
Private Sub cboSRat_AfterUpdate()
Me.Form.Requery
End Sub
If needing to capture rows with potential NULLs, integrate OR conditions:
SQL
SELECT *
FROM Lieferant
WHERE ([Bezeichner] = NZ(Forms!myForm!cboLiefName, [Bezeichner])
OR (Forms!myForm!cboLiefName IS NULL AND [Bezeichner] IS NULL)
)
AND ([S_Rating] = NZ(Forms!myForm!cboSRat, [S_Rating])
OR (Forms!myForm!cboSRat IS NULL AND [S_Rating] IS NULL)
)
AND ([Verantwortlicher] = NZ(Forms!myForm!cboVerant, [Verantwortlicher])
OR (Forms!myForm!cboVerant IS NULL AND [Verantwortlicher] IS NULL)
)
AND ([Lieferantenkategorie] = NZ(Forms!myForm!cboLiefKat, [Lieferantenkategorie])
OR (Forms!myForm!cboLiefKat IS NULL AND [Lieferantenkategorie]IS NULL)
)
AND ([Lieferantenart] = NZ(Forms!myForm!cboliefart, [Lieferantenart])
OR (Forms!myForm!cboliefart IS NULL AND [Lieferantenart] IS NULL)
)
AND ([Land] = NZ(Forms!myForm!cboLand, [Land])
OR (Forms!myForm!cboLand IS NULL AND [Land] IS NULL)
)
AND ([Audit_Ergebnis] = NZ(Forms!myForm!cboAudErg, [Audit_Ergebnis])
OR (Forms!myForm!cboAudErg AND [Audit_Ergebnis] IS NULL)
)

Somehow you (your code) must expand the where clause, for example:
myLieferantName = "Select * from Lieferant where [Bezeichner] = '" & Me.cboLiefName & "' And [Land] = '" & Me.cboLand & "'"
As a side note, a requery isn't needed after adjusting the recordsource:
Me.RecordSource = myLieferantName
' Me.Form.Requery

Related

Ms Access VBA - Trying to call data from a combo box but only if a field is empty

From the code below I want [KronosNO] to come from a database Combo box
but only if the [RTWDate] column is Null.
Set Rs = Application.CurrentDb.OpenRecordset(
"SELECT * FROM tblAbsence WHERE [KronosNo] = '" & Me.cmbKronosNo.Value & "'
AND [RTWDate] = '" & "Is Null" & "' ", dbOpenDynaset)
Don't treat Is Null like a variable, it is a part of SQL.
You simply need
AND [RTWDate] Is Null
in your string.

MS Access - Editing fields after making them autopopulate only edits 1st record (forms)

Just a headsup, I am quite new to relational databases so my question could be a simple fix.
Currently, I have a table with the following data.
ID(1 ,2,3,4,5)
Location(Canada, USA, Japan, Australia, Venezuela)
Count(4,6,2,91,23)
I created a form with a combobox and two text fields. The goal is that I want to be able to click the combobox, have it show all the ID's and when I click an ID, it autopopulates the other two text fields with the corresponding information. After googling a bit, I found a way to do is. Within the Event tab under "on Change" for the combobox, I wrote the these two lines of code.
Me.txtLocation = Me.cboID.Column(1)
Me.txtCount = Me.cboID.Column(2)
However, I also want to be able to edit this information once it has been autopopulated. The problem I'm having is that when I change any of the two textfields, it always edits the first records.
So for example, if I click ID #4, and I change the "Count", it will change the "Count" for the ID #1. Any idea of what I'm doing wrong?
P.S. (I have programming experience but not with VBA)
Thanks in advance!
EDIT:
Private Sub txtCount_AfterUpdate()
Dim strSQL As String
strSQL = "UPDATE aDuh SET Count = '" & Me.Count & "', Location = '" & Me.txtLocation & "' WHERE ID = " & Me.cboID & ""
DoCmd.RunSQL (strSQL)
End Sub
Private Sub txtLocation_AfterUpdate()
Dim strSQL As String
strSQL = "UPDATE aDuh SET Location = '" & Me.txtLocation & "', Count = '" & Me.txtCount & "' WHERE ID = " & Me.cboID & ""
DoCmd.RunSQL (strSQL)
End Sub
Don't bind your form to a table. Put a textbox on your form with it's Visible property set to False. In that textbox, put the value of your Primary Key field (which should be an AutoNumber field) Then when you update your record, pass an UPDATE SQL statement where you update your table based on the value of your Primary Key
Dim strSQL as String
strSQL = "UPDATE aDuh SET Location = '" & Me.txtLocation & "', Count = '" & Me.txtCount & "' WHERE ID = " & Me.cboID & ""
DoCmd.RunSQL (strSQL)

select [combobox value] & "text"

I am trying to build SELECT statement in Access VBA, based on value chosen by user in ComboBox.
Example :
"SELECT [8_SV_RT] FROM DATA WHERE condition = value
I need 8 to be dependent on ComboBox value from form. (8,10,12 ....)
The name of ComboBox is DN, and I created string COL = "_SV_RT"
So far I have :
"SELECT [DN] & '" & COL & "' FROM DATA WHERE condition = value
It returns value 8_SV_RT to ComboBox, which I want to use after SELECT statement, but not as result. I must be missing some syntax or something? Can anyone please advise?
If I understand your question right:
Dim SQL As String
SQL = "SELECT [" & Me.MyComboBox & "_SV_RT] FROM DATA WHERE condition = value"
EDIT:
To use the exact object names from the question (before Siddharth edited it, I over-read that the combobox is named DN) and to take Siddharth's (now deleted) comment into consideration:
Dim SQL As String
Dim COL As String
COL = "_SV_RT"
SQL = "SELECT [" & DN & COL & "] FROM DATA WHERE condition = value"

If/Then in SQL Embedded in VBA

I've got a string like this in my Excel VBA:
strSQL = "SELECT * FROM Total WHERE (SimulationID = (" & TextBox1.Text & ") And Test1 = (" & Example & "))"
However, sometimes Test will be 'is null', which makes the query
And Example = is NULL
How can I change it to add an if/then statement or something to make it say
And Example is null
when Example has a value of "is null"?
I would suggest doing the NULL comparison before assembling the SQL statement strSQL.
If you check for the value of Example beforehand, you can alter your strSQL statement accordingly based on that check.
EDIT:
In response to Daniel's first and second comment below, I still would prefer the following over doing it inline:
Dim strSqlTail
strSqlTail = ""
If (Example1 = Null) Then strSqlTail = "AND Example1 IS NULL"
If (Example2 = Null) Then strSqlTail = strSqlTail & "AND Example2 IS NULL"
If (Example3 = Null) Then strSqlTail = strSqlTail & "AND Example3 IS NULL"
...
Note: The strSqlTail can be whatever SQL would make your situation work since I don't quite understand what is being queried from the sample.
You just create a function that puts the equal sign and space before the number if it doesn't equal "is null", and modify the string assignment statement appropriately, like so:
Public Function NullModString(Example As String) As String
If Example <> "is null" Then Example = "= " & Example
NullModString = Example
End Function
strSQL = "SELECT * FROM Total WHERE SimulationID = " & TextBox1.Text & _
"And Test1 " & NullModString(Example)
Note, that I didn't understand why the extra parentheses were in there, but it would be simple to put them back in.
One solution is to coalesce out the null using a Coalesce function (or if using Access, the Nz function) :
trSQL = "SELECT ..." & _
" FROM Total" & _
" WHERE SimulationID = " & TextBox1.Text & " & _
" And Coalesce(Test1,"""") = "" & Example & """
A better way would be to dynamically include or not include the entire And statement based on whether Example had a value or to substitute Test Is Null when Example did not have a value. So something akin to:
Dim testElements() As Variant
Dim vElement As Variant
Redim testElements(6,1)
testElements(0,0) = Example1
testElements(0,1) = "Test1"
testElements(1,0) = Example2
testElements(1,1) = "Test2"
...
Dim elementIndex as Integer
Dim colName As String
Dim elementValue As Variant
For elementIndex = 0 To UBound(testElements)
elementValue = testElement(elementIndex, 0)
colName = testElement(elementIndex, 1)
If Len(Nz(elementValue)) = 0 Then
trSQL = trSQL & " And " & colName & " = """ & Example1 & """
Else
trSQL = trSQL & " And " & colName & " Is Null"
End If
Next
First, don't embed SQL in VBA: hard to maintain, SQL injection, etc. Use a stored proc on the database side (even Access has PROCEDUREs).
Second, use COALESCE (or equivalent logic) to handle your 'empty string equates to NULL' UI logic. You don't say which SQL syntax and you haven't posted schema DLL so we're merely guessing...
SQL Server:
CREATE PROCEDURE GetTotals
#SimulationID INTEGER,
#Test1 VARCHAR(20) = NULL
AS
SELECT *
FROM Total AS T1.
WHERE T1.SimulationID = #SimulationID
AND COALESCE(T1.Test1, '') = COALESCE(#Test1, '');
Access Database Engine (a.k.a. Jet):
CREATE PROCEDURE GetTotals
(
:SimulationID INTEGER,
:Test1 VARCHAR(20) = NULL
)
AS
SELECT *
FROM Total AS T1
WHERE T1.SimulationID = :SimulationID
AND IIF(T1.Test1 IS NULL, '', T1.Test1)
= IIF(:Test1 IS NULL, '', :Test1);
Then execute the proc using your middleware (ADO, DAO, etc) with Parameter objects, using the empty string (or other 'magic' value) for NULL.

Query will not run with variables, will work when variable's definitions are pasted in

This is a Query in VBA (Access 2007)
I have 3 strings defined:
str_a = "db.col1 = 5"
str_b = " and db.col2 = 123"
str_c = " and db.col3 = 42"
Then I use these in the WHERE part of my Query:
"WHERE '" & str_a & "' '" & str_b & "' '" & str_c & "' ;"
This fails, but If I paste in the strings like this:
"WHERE db.col1 = 5 and db.col2 = 123 and db.col3 = 42;"
It works perfectly. I'm guessing the syntax is wrong when using multiple variables in a string.
Anyone have any hints?
"WHERE '" & str_a & "' '" & str_b & "' '" & str_c & "' ;"
will include single quotes within your completed WHERE clause. And the working version you showed us has none:
"WHERE db.col1 = 5 and db.col2 = 123 and db.col3 = 42;"
So, try constructing the WHERE clause with no single quotes:
"WHERE " & str_a & " " & str_b & " " & str_c & ";"
For debugging purposes, it's useful to view the final string after VBA has finished constructing it. If you're storing the string in a variable named strSQL, you can use:
Debug.Print strSQL
to display the finished string in the Immediate Window of the VB Editor. (You can get to the Immediate Window with the CTRL+g keyboard shortcut.)
Alternatively, you could display the finished string in a message box window:
MsgBox strSQL
You've got some extra single quotes in there.
Try this:
"WHERE " & str_a & str_b & str_c
Note: In general, you shouldn't build query strings by concatenating strings, because this leaves you vulnerable to SQL injection, and mishandles special characters. A better solution is to use prepared statements. But assuming you're operating in a very controlled environment the solution I gave should work.
Quick tip about troubleshooting SQL that is built dynamically: echo the SQL string resulting from all the concatenation and interpolation, instead of staring at your code.
WHERE 'db.col1 = 5' ' and db.col2 = 123' ' and db.col3 = 42';
Nine times out of ten, the problem becomes a lot more clear.
For VB6/VBA dynamic SQL, I always find it more readable to create an SQL template, and then use the Replace() function to add in the dynamic parts. Try this out:
Dim sql As String
Dim condition1 As String
Dim condition2 As String
Dim condition3 As String
sql = "SELECT db.col1, db.col2, db.col3 FROM db WHERE <condition1> AND <condition2> AND <condition3>;"
condition1 = "db.col1 = 5"
condition2 = "db.col2 = 123"
condition3 = "db.col3 = 'ABCXYZ'"
sql = Replace(sql, "<condition1>", condition1)
sql = Replace(sql, "<condition2>", condition2)
sql = Replace(sql, "<condition3>", condition3)
However, in this case, the values in the WHERE clause would change, not the fields themselves, so you could rewrite this as:
Dim sql As String
sql = "SELECT col1, col2, col3 FROM db "
sql = sql & "WHERE col1 = <condition1> AND col2 = <condition2> AND col3 = '<condition3>';"
sql = Replace(sql, "<condition1>", txtCol1.Text)
sql = Replace(sql, "<condition2>", txtCol2.Text)
sql = Replace(sql, "<condition3>", txtCol3.Text)
Some comments on constructing WHERE clauses in VBA.
Your example is by definition going to be incorrect, because you're putting single quotes where they aren't needed. This:
str_a = "db.col1 = 5"
str_b = " and db.col2 = 123"
str_c = " and db.col3 = 42"
"WHERE '" & str_a & "' '" & str_b & "' '" & str_c & "' ;"
...will produce this result:
WHERE 'db.col1 = 5' ' and db.col2 = 123' ' and db.col3 = 42' ;
This is obviously not going to work.
Take the single quotes out and it should work.
Now, that said, I'd never do it that way. I'd never put the AND in the substrings that are used to construct the WHERE clause, because what would I do if I have a value for the second string but not for the first?
When you have to concatenate a number of strings with a delimiter and some can be unassigned, one thing to do is to just concatenate them all and not worry if the string before the concatenation is unassigned of not:
str_a = "db.col1 = 5"
str_b = "db.col2 = 123"
str_c = "db.col3 = 42"
To concatenate that, you'd do:
If Len(str_a) > 0 Then
strWhere = strWhere & " AND " str_a
End If
If Len(str_b) > 0 Then
strWhere = strWhere & " AND " str_b
End If
If Len(str_c) > 0 Then
strWhere = strWhere & " AND " str_c
End If
When all three strings are assigned, that would give you:
" AND db.col1 = 5 AND db.col2 = 123 AND db.col3 = 42"
Just use Mid() to chop of the first 5 characters and it will always come out correct, regardless of which of the variables have values assigned:
strWhere = Mid(strWhere, 6)
If none of them are assigned, you'll get a zero-length string, which is what you want. If any one of them is assigned, you'll first get " AND ...", which is an erroneous leading operator, which you just chop out with the Mid() command. This works because you know that all the results before the Mid() will start with " AND " no matter what -- no needless tests for whether or not strWhere already has been assigned a value -- just stick the AND in there and chop it off at the end.
On another note, someone mentioned SQL injection. In regards to Access, there was a lengthy discussion of that which considers a lot of issues close to this thread:
Non-Web SQL Injection
I have my favorite "addANDclause" function, with the following parameters:
public addANDclause( _
m_originalQuery as string, _
m_newClause as string) _
as string
if m_originalQuery doe not contains the WHERE keyword then addANDClause() will return the original query with a " WHERE " added to it.
if m_orginalQuery already contains the WHERE keyword then addANDClause() will return the original query with a " AND " added to it.
So I can add as many "AND" clauses as possible. With your example, I would write the following to create my SQL query on the fly:
m_SQLquery = "SELECT db.* FROM db"
m_SQLquery = addANDClause(m_SQLQuery, "db.col1 = 5")
m_SQLQuery = addANDClause(m_SQLQuery, "db.col2 = 123")
m_SQLQuery = addANDClause(m_SQLQuery, "db.col3 = 42")
Of course, instead of these fixed values, such a function can pick up values available in bound or unbound form controls to build recordset filters on the fly. It is also possible to send parameters such as:
m_SQLQuery = addANDClause(m_SQLQuery, "db.text1 like 'abc*'")
While dynamic SQL can be more efficient for the engine, some of the comments here seem to endorse my view that dynamic SQL can be confusing to the human reader, especially when they didn't write the code (think of the person who will inherit your code).
I prefer static SQL in a PROCEDURE and make the call to the proc dynamic at runtime by choosing appropriate values; if you use SQL DDL (example below) to define the proc you can specify DEFAULT values (e.g. NULL) for the parameters so the caller can simply omit the ones that are not needed e.g. see if you can follow the logic in this proc:
CREATE PROCEDURE MyProc
(
arg_col1 INTEGER = NULL,
arg_col2 INTEGER = NULL,
arg_col3 INTEGER = NULL
)
AS
SELECT col1, col2, col3
FROM db
WHERE col1 = IIF(arg_col1 IS NULL, col1, arg_col1)
AND col2 = IIF(arg_col2 IS NULL, col2, arg_col2)
AND col3 = IIF(arg_col3 IS NULL, col3, arg_col3);
Sure, it may not yield the best execution plan but IMO you have to balance optimization against good design principles (and it runs really quick on my machine :)