VBA - SQL with optional joins - vba

I have a combolist where I can select multiple values, but if I leave them all blank then I want to exclude that portion from the query. Here is the current logic I'm using
If ModeCat_ID = "" Then
Set rs = conn.Execute("SELECT * FROM [ModeCat_T]")
Else
Set rs = conn.Execute("SELECT * FROM [ModeCat_T] WHERE [ModeCat_ID] = '" & ModeCat_ID & "'")
End If
My question is, is this the best way to go about this? I'm building a form that has a few more options so I'd rather not have a bunch of tested Ifs to check these form controls.
Second question is, if it's a combo box that can select multiples.. how would I set that up for an SQL IN statement? ie
IN ('1','2','3')
Thanks!
EDIT
Set rs = conn.Execute("SELECT * FROM [ModeCat_T]")

This is how I normally do it:
Dim strSQL As String
strSQL = "set nocount on; "
strSQL = strSQL & "select * "
strSQL = strSQL & "from [ModeCat_T] "
strSQL = strSQL & " where 1 = 1 "
'*******************************************************
'* Adding the other where restrictions as necessary
'*******************************************************
If Trim(Sheet1.Range("B7").Value2) <> vbNullString Then
strSQL = strSQL & " and [ModeCat_ID] = '" & Sheet1.Range("B7").Value2 & "' "
End If
If Trim(Sheet1.Range("B8").Value2) <> vbNullString Then
strSQL = strSQL & " and [ModeCat_Color] = '" & Sheet1.Range("B8").Value2 & "' "
End If
If Trim(Sheet1.Range("B9").Value2) <> vbNullString Then
strSQL = strSQL & " and [ModeCat_Size] = '" & Sheet1.Range("B9").Value2 & "' "
End If
Set rs = conn.Execute(strSQL)
Following the continued discussion about "Filters" where you can select possibly many different items from a ListBox the following code might be able to help with that:
Dim strFilter As String
Dim lngItem As Long
For lngItem = 0 To UserForm1.ListBox1.ListCount - 1
If UserForm1.ListBox1.Selected(lngItem) = True Then
If strFilter <> vbNullString Then strFilter = strFilter & ", "
strFilter = strFilter & "'"
strFilter = strFilter & UserForm1.ListBox1.List(lngItem, 1)
strFilter = strFilter & "'"
End If
Next lngItem
If strFilter <> vbNullString Then
strSQL = strSQL & "and [ModeCat_Form] in (" & strFilter & ") "
End If
Basically, it is checking which items from the list have been selected and puts them into a string (wrapped in ' and separated by a comma). Afterwards the code checks if anything made it into the "Filter String". If the filter is not empty then it should be used. BTW: it does not matter if the string contains one or many items. So, this is also permissible:
AND [ModeCat_Shape] in ('Oval')

I felt I should expand my comment the #Ralphs answer with a more maintainable solution.
As you're using a ComboBox and by the sound of it your wanting the user to be able to select multiple columns, use a ListBox instead. I would hide the reference to the field name in the first column of the ListBox by setting it's column width to 0. Then in the next column, you could add the actual filter in there.
Once this is done, you can iterate through the selected items to apply the filters like so:
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
strSQL = " AND " & ListBox1.Column(0, i) & " = '" & ListBox1.Column(1, i) & "'"
End If
Next i

Related

MS. Access - VBA SQL string not returning any records

As part of a larger project I'm trying to copy records from one table to another but I'm stuck on the first step trying to get the records from the 1st table
My strSQL string in VBA is not returning any record's at the .RecordCount but it should be 2
The SQL from the query builder is
SELECT tbl_BOM_Requirments.ID, tbl_BOM_Requirments.PrtNmber_LinkField, tbl_BOM_Requirments.RequiredMaterialPrtNum, tbl_BOM_Requirments.RequiredMaterialDescription FROM tbl_BOM_Requirments WHERE (((tbl_BOM_Requirments.PrtNmber_LinkField)="PRT468"));
That works fine.. PRT468 is the current record - in VBA I'm using a variable PrtNbrGt
Private Sub Command15_Click()
Dim rstSource As DAO.Recordset
Dim rstInsert As DAO.Recordset
Dim fld As DAO.Field
Dim strSQL As String
Dim lngLoop As Long
Dim lngCount As Long
Dim PrtNbrGt As String
PrtNbrGt = Me.SCSPartNumb
strSQL = "SELECT tbl_BOM_Requirments.RequiredMaterialPrtNum" & vbCrLf & _
"FROM tbl_BOM_Requirments" & vbCrLf & _
"WHERE (tbl_BOM_Requirments.PrtNmber_LinkField) = "" & PrtNbrGt"""
Set rstInsert = CurrentDb.OpenRecordset(strSQL)
Set rstSource = rstInsert.Clone
With rstSource
lngCount = .RecordCount
For lngLoop = 1 To lngCount
Has anyone got any suggestions why it's not returning any records?
You need to replace the double quotes in your working SELECT with single quotes as the doubles quotes are in use to delimiter the string
strSQL = "SELECT tbl_BOM_Requirments.RequiredMaterialPrtNum " & vbCrLf & _
"FROM tbl_BOM_Requirments " & vbCrLf & _
"WHERE (tbl_BOM_Requirments.PrtNmber_LinkField) = '" & Replace(PrtNbrGt, "'", "''") & "'"
But your code should have goven you some errors anyway
but you can use parameters see https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/parameters-declaration-microsoft-access-sql
You are tangled up in double quote inception. Instead:
"WHERE (tbl_BOM_Requirments.PrtNmber_LinkField) = """ & PrtNbrGt & """"
You could also do:
"WHERE (tbl_BOM_Requirments.PrtNmber_LinkField) = " & CHR(34) & PrtNbrGt & CHR(34)
That's a little easier to read. CHR(34) that is used in this example is a literal double quote.

Have a List box that Filters on items within my subform that is a query

I have a list box that has three different categories to choose from on the form. I have vba code that is working that allows me to select more than one item in the list box which is fine. But the items I am selecting I am having troubles to get the results that I need.
For an Example; The three categories within the list box are not in the query with the actual category names. One Category I have is called "Picking" okay, I want to select "picking" and then when the button is clicked I want it to pull all Items within the query field "Item Number" that equals '0801' which represents the Category "Picking".
Note the code behind the button is a simple "On Click" Event Procedure
**The List box I am Having troubles with is called (StrAccounts)
**Picking which is the same thing as Acct in the query that I am trying filter on in in tbUpload
**I want the "Picking" Category in the List box to filter on Acct in the query where Acct = '0801'
**Placed_Orders which the Second category name within my ListBox and it is the same field in the query above "tbUpload", Acct, except I want
this Placed_Orders to get all Acct in ('1108', '1114', '1117', '1113',
'1110')
**Whatever Acct in the query tbUpload that doesn't contain the following numbers already mention above is the third category in my
list box which is "Not_Placed"
**So whenever Not_Placed in the list box is clicked and the search button is selected I want Accts in the query to pull, Accts <>
'0801','1108','1114','1117','1113','1110'
Private Sub cmdSearch_Click()
Dim Varitem As Variant
Dim StrDEPT_OBS As String
Dim StrStatus As String
Dim StrACCT As String
Dim strSQL As String
Dim StrAccounts As String
'get selections from DEPT_OBS multiselect listbox
For Each Varitem In Me!List_Dept_OBS.ItemsSelected
StrDEPT_OBS = StrDEPT_OBS & ",'" & Me!List_Dept_OBS.ItemData(Varitem) & "'"
Next
'get selections from Status multiselect listbox
For Each Varitem In Me!List_Status.ItemsSelected
StrStatus = StrStatus & ",'" & Me!List_Status.ItemData(Varitem) & "'"
Next
'get selections from Accts multiselect listbox
For Each Varitem In Me!List_ACCTs.ItemsSelected
StrStatus = StrAccounts & ",'" & Me!List_ACCTs.ItemData(Varitem) & "'"
Next
If Len(StrDEPT_OBS) > 0 Then
StrDEPT_OBS = Right(StrDEPT_OBS, Len(StrDEPT_OBS) - 1)
Else: MsgBox "You must enter an OBS"
Exit Sub
End If
If Len(StrStatus) > 0 Then
StrStatus = Right(StrStatus, Len(StrStatus) - 1)
End If
If Len(StrAccounts) > 0 Then
StrAccounts = Right(StrAccounts, Len(StrAccounts) - 1)
End If
strSQL = " SELECT * FROM tbUpload WHERE "
strSQL = strSQL & "tbUpload.DEPT_ID IN (" & StrDEPT_OBS & ") AND "
If Len(StrStatus) = 0 Then
strSQL = strSQL & "tbUpload.DEPT_ID IN (" & StrDEPT_OBS & ") "
Else
strSQL = strSQL & "tbUpload.OPR_STAT_ID IN (" & StrStatus & ") "
End If
If Len(StrAccounts) = 0 And StrAccounts = "Picking" Then
strSQL = strSQL & "tbUpload.ACCT like (" & [0801] & ")"
Else
End If
If Len(StrAccounts) = 0 And StrAccounts = "Placed_Orders" Then
strSQL = strSQL & "tbUpload.ACCT IN (" & [1108] & [1114] & [1117] & [1113] & [1110] & ") "
Else
strSQL = strSQL & "tbUpload.ACCT <> (" & [0801] & [1108] & [1114] & [1117] & [1113] & [1110] & ") " "Not_Placed"
End If
DoCmd.SetWarnings False
''DoCmd.OpenQuery ("UPLOAD")
Me![tbUpload subform].Form.RecordSource = strSQL
End Sub
If Len(StrAccounts) > 0 Then
'' StrAccounts = Right(StrAccounts, Len(StrAccounts) - 1)
StrAccounts = StrAccounts & ",'" & Me!List_ACCTs.ItemData(Varitem) & "'"
End If
strSQL = " SELECT * FROM tbUpload WHERE "
strSQL = strSQL & "tbUpload.DEPT_ID IN (" & StrDEPT_OBS & ") AND "
If Len(StrStatus) = 0 Then
strSQL = strSQL & "tbUpload.DEPT_ID IN (" & StrDEPT_OBS & ") "
Else
strSQL = strSQL & "tbUpload.OPR_STAT_ID IN (" & StrStat us & ") "
End If
If StrAccounts = "Lugging" Then
strSQL = strSQL & "tbUpload.ACCT like (" & [0801] & ")"
Else
End If
If StrAccounts = "Structure" Then
strSQL = strSQL & "tbUpload.ACCT IN (" & [1108] & [1114] & [1117] & [1113] & [1110] & ") "
Else
End If
Consider:
'get selections from DEPT_OBS multiselect listbox
For Each Varitem In Me.List_Dept_OBS.ItemsSelected
StrDEPT_OBS = StrDEPT_OBS & ",'" & Me.List_Dept_OBS.ItemData(Varitem) & "'"
Next
If Len(StrDEPT_OBS) > 0 Then
StrDEPT_OBS = "[Dept_ID] IN(" & Right(StrDEPT_OBS, Len(StrDEPT_OBS) - 1) & ") AND "
Else
MsgBox "You must enter an OBS"
Exit Sub
End If
'get selections from Status multiselect listbox
For Each Varitem In Me.List_Status.ItemsSelected
StrStatus = StrStatus & ",'" & Me.List_Status.ItemData(Varitem) & "'"
Next
If Len(StrStatus) > 0 Then
StrStatus = "[OPR_STAT_ID] IN(" & Right(StrStatus, Len(StrStatus) - 1) & ") AND "
End If
'get selection from Accts single select listbox and build account parameters array
Select Case Me.List_Accts
Case "Picking"
StrAccounts = "ACCT = 0801 AND "
Case "Placed_Orders"
StrAccounts = "ACCT IN(1108,1114,1117,1113,1110) AND "
Case "Not_Placed"
StrAccounts = "NOT ACCT IN(0801,1108,1114,1117,1113,1110) AND "
End Select
strSQL = StrDEPT_OBS & StrStatus & StrAccounts
If strSQL <> "" Then
strSQL = " WHERE " & Left(strSQL, Len(strSQL) - 5)
End If
Me.[tbUpload subform].Form.RecordSource = "SELECT * FROM tbUpload" & strSQL & ";"
For more info on dynamically building search criteria with VBA, review http://allenbrowne.com/ser-62.html

Update SQL MS Access 2010

This is wrecking my brains for 4 hours now,
I have a Table named BreakSked,
and I this button to update the table with the break end time with this sql:
strSQL1 = "UPDATE [BreakSked] SET [BreakSked].[EndTime] = " & _
Me.Text412.Value & " WHERE [BreakSked].AgentName = " & Me.List423.Value _
& " AND [BreakSked].ShiftStatus = '1'"
CurrentDB.Execute strSQL1
Text412 holds the current system time and List423 contains the name of the person.
I'm always getting this
"Run-time error 3075: Syntax Error (missing operator) in query
expression '03:00:00 am'
Any help please?
EDIT: Thanks, now my records are updating. But now its adding another record instead of updating the record at hand. I feel so silly since my program only has two buttons and I can't figure out why this is happening.
Private Sub Form_Load()
DoCmd.GoToRecord , , acNewRec
End Sub
Private Sub Command536_Click()
strSQL1 = "UPDATE BreakSked SET BreakSked.EndTime = '" & Me.Text412.Value & "',BreakSked.Duration = '" & durationz & "' " & vbCrLf & _
"WHERE (([BreakSked].[AgentID]='" & Me.List423.Value & "'));"
CurrentDb.Execute strSQL1
CurrentDb.Close
MsgBox "OK", vbOKOnly, "Added"
End Sub
Private Sub Command520_Click()
strSql = "INSERT INTO BreakSked (ShiftDate,AgentID,StartTime,Status) VALUES ('" & Me.Text373.Value & "', '" & Me.List423.Value & "', '" & Me.Text373.Value & "','" & Me.Page657.Caption & "')"
CurrentDb.Execute strSql
CurrentDb.Close
MsgBox "OK", vbOKOnly, "Added"
End Sub
You wouldn't need to delimit Date/Time and text values if you use a parameter query.
Dim strUpdate As String
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
strUpdate = "PARAMETERS pEndTime DateTime, pAgentName Text ( 255 );" & vbCrLf & _
"UPDATE BreakSked AS b SET b.EndTime = [pEndTime]" & vbCrLf & _
"WHERE b.AgentName = [pAgentName] AND b.ShiftStatus = '1';"
Debug.Print strUpdate ' <- inspect this in Immediate window ...
' Ctrl+g will take you there
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", strUpdate)
qdf.Parameters("pEndTime").Value = Me.Text412.Value
qdf.Parameters("pAgentName").Value = Me.List423.Value
qdf.Execute dbFailOnError
And if you always want to put the current system time into EndTime, you can use the Time() function instead of pulling it from a text box.
'qdf.Parameters("pEndTime").Value = Me.Text412.Value
qdf.Parameters("pEndTime").Value = Time() ' or Now() if you want date and time
However, if that is the case, you could just hard-code the function name into the SQL and dispense with one parameter.
"UPDATE BreakSked AS b SET b.EndTime = Time()" & vbCrLf & _
As I said in my comment you need to wrap date fields in "#" and string fields in escaped double quotes
strSQL1 = "UPDATE [BreakSked] SET [BreakSked].[EndTime] = #" & _
Me.Text412.Value & "# WHERE [BreakSked].AgentName = """ & Me.List423.Value & _
""" AND [BreakSked].ShiftStatus = '1'"

Combobox filtering for listbox output is not working as expected

I have a few controls (Combobox's I call DDL's) that I use as filters for a dynamic query, shown below.
I have a region, division filter - and BCI/BCV/ABC/etc dropdowns.
When I select the region and division, the output list box correctly filters out everything except THOSE region/divisions. Good.
The problem comes in when I use the other DDL's, ABD/BCI/etc... those do not filter out correctly and I think it is with my and/or clauses below.
Can anyone see anything glaring or point me in the right direction to get this so that every control and ddl element filters out the data it is intended for - while keeping it in a format where the SQL itself is part of a string, like in my example?
Private Sub goBtn_Click()
strSQL = "SELECT [account_number], [BCI_Amt], [BCV_Amt],[ABC_Amt], [other_Amt], " & _
"[BCI_Amt]+[BCV_Amt]+[ABC_Amt]+[other_MRC_Amt], Division_Name, Region_Name, " & _
"Tier, Unit_ID, Name, Description_2 " & _
"FROM dbo_ndw_bc_subs " & _
"WHERE DivisionDDL = [Division_Name] and RegionDDL = [Region_Name] " & _
" and ( [BCI_Ind] = CheckBCI.value or [BCV_Ind] = CheckBCV.value or [ABC_Ind] = CheckABC.value " & _
" or BCIServiceDDL = [Tier]" & _
" or BCVServiceDDL = [Description_2]" & _
" or ABCServiceDDL = [Unit_ID] )" & _
"ORDER BY 6 asc"
Me.output1.RowSource = strSQL
End Sub
One of the combo box DDL control codes. There are check boxes that make the combo box visible or not visible.
Private Sub CheckBCV_Click()
If Me.CheckBCV = vbTrue Then
Me.BCVServiceDDL.Visible = True
Me.BCVServiceDDL = "Select:"
strSQL = "SELECT Distinct subs.[Description_2] FROM dbo_ndw_bc_subs "
Me.BCVServiceDDL.RowSource = strSQL
Me.BCVServiceDDL.Requery
Else
Me.BCVServiceDDL.Visible = False
Me.BCVServiceDDL = ""
End If
End Sub
Edit: Added additional code to the first code block for context, and updated some comments.
To reiterate the point of my question - Since some of the DDL's work as expected while the others do not. Is it in the AND/OR section where I have a problem - or am I forced to do an IF/IIF statement in the select. (And if I do this IF solution - how would that be incorporated into a string the way I have it now, I have not seen an example of this in my research on a resolution).
I think your top code sample should read more like this:
Private Sub goBtn_Click()
Dim strSQL As String
Dim strWhere As String
Dim strOp As String
strSQL = "SELECT [account_number], [BCI_Amt], [BCV_Amt],[ABC_Amt], [other_Amt], " & _
"[BCI_Amt]+[BCV_Amt]+[ABC_Amt]+[other_MRC_Amt], Division_Name, Region_Name, " & _
"Tier, Unit_ID, Name, Description_2 " & _
"FROM dbo_ndw_bc_subs "
strWhere = ""
strOp = ""
If Not IsNull(Me.DivisionDDL.Value) Then
strWhere = strWhere & strOp & "(Division_Name = """ & Me.DivisionDDL.Value & """)"
strOp = " And "
End If
If Not IsNull(Me.RegionDDL.Value) Then
strWhere = strWhere & strOp & "(Region_Name = """ & Me.RegionDDL.Value & """)"
strOp = " And "
End If
If Me.CheckBCI.Value Then
strWhere = strWhere & strOp & "(Tier = """ & Me.BCIServiceDDL.Value & """)"
strOp = " And "
End If
If Me.CheckBCV.Value Then
strWhere = strWhere & strOp & "(Description_2 = """ & Me.BCVServiceDDL.Value & """)"
strOp = " And "
End If
If Me.CheckABC.Value Then
strWhere = strWhere & strOp & "(Unit_ID = """ & Me.ABCServiceDDL.Value & """)"
strOp = " And "
End If
If Len(strWhere) > 0 then
strSQL = strSQL & " WHERE " & strWhere
End If
strSQL = strSQL & " ORDER BY 6 asc"
Me.output1.RowSource = strSQL
End Sub
This is wordier, but much closer to correct. P.S. I guessed that all values are strings. If not remove the quoting around non-string values.

Why is an action query not working in access VBA?

I tested an UPDATE query in Access's query design, and it works, but when I try to use it in my module, I get the error:
Invalid SQL statement; expected... or 'UPDATE'.
My query:
strSql = "UPDATE " & rs.Fields("tableName") & _
" SET " & rs.Fields("foreignKeyName") & " = " & rsContacts.Fields("contactId") & _
" WHERE contactId = " & ContactID
rs: a table that has tableName, foriegnKeyName of the tables to update
rsContacts: a list of contactIds (currently standing on a particular one).
The actual string comes out like this:
UPDATE myTable SET ContactId = 5 WHERE contactId = 2
If the query works, and it is an action query, why am I getting this error?
This is my full code:
Public Sub updateChildTables(ByVal ContactID As Long, ByVal CompanyID As Long)
Dim strSql As String
Dim rs As Recordset
Dim rsPending As Recordset
strSql = "SELECT contactID FROM contacts _
WHERE companyId = " & CompanyID & " and contactId <> " & ContactID
Set rs = CurrentDb.OpenRecordset(strSql)
If Not (rs.BOF And rs.EOF) Then
rs.MoveFirst
strSql = "SELECT * FROM childTables"
Set rsChild = CurrentDb.OpenRecordset(strSql)
rsChild.MoveFirst
Do While Not rsChild.EOF
strSql = "UPDATE " & rsChild.Fields("tableName") & " SET " & rsChild.Fields("foreignKeyName") & " = " & rs.Fields("contactId") & " WHERE contactId = " & ContactID
DoCmd.RunSQL strSql
rs.moveNext
Loop
rsChild.Close
Set rsChild = Nothing
End If
Here is my idea for debugging and possibly even resolving this.
Create a query from within Access normally -- name it UpdateMyTable, for the sake of this example.
Then, rather than using the DoCmd, actually execute this specific query from your VBA.
Dim qry As QueryDef
strSql = "UPDATE " & rsChild.Fields("tableName") & " SET " & _
rsChild.Fields("foreignKeyName") & " = " & _
rs.Fields("contactId") & " WHERE contactId = " & ContactID
Set qry = CurrentDb.QueryDefs("UpdateMyTable")
qry.SQL = strSql
qry.Execute
The big advantage of this is that you can very easily debug this from within Access to both see the rendered SQL and manually run it / tweak it.