changing sql string based on active userform - sql

I have a SQL query that I'm calling from a couple of different forms using the ctrl as object method. It works fine, but when I run it from a click event it will also open whichever form isn't currently loaded. The query returns the results I want, it just does it to both forms at the same time regardless of which is loaded.
Only one form is loaded at a time. A drop down list called Team exists on both forms. The query passes the currently selected item from that drop down list to return a list of agents assigned to that team.
I know that part of the issue is my query using an or statement that refers to values on both forms, but I'm not sure how to change it to reference the active form.
Attendance and reporting are the names of the two UserForms currently calling this query. Both of them have combobox controls named Team. I've tried activeform, etc. But I can't seem to find a way to make it work.
Sub agents(ctrl As Object)
database_connect
Dim SQLStr As String
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Dim Counter As Long
SQLStr="select distinct[Agentname] from dbo.[Attendance] Where [Team]='" & _
attendance.Team.Value & "' or [Team] ='" & Reporting.Team.Value & "'"
If appconn.State = 0 Then
Call database_connect
End If
rs.Open SQLStr, appconn, adOpenStatic
With ctrl
Do
.AddItem rs![Agentname]
rs.MoveNext
Loop Until rs.EOF
End With
rs.Close
database_Disconnect
Set rs = Nothing
Exit Sub
End Sub

1) Well first off to refer to controls you have to have the form loaded.
2) Youre referring to controls in the oddest way. Review AND save this URL http://access.mvps.org/access/forms/frm0031.htm
3) If one form is closed your query might always return nothing. Is this a desired output?

For anyone who may find this looking for something similar, this is the solution I used.
I used a Function to test if a userform is loaded or not.
Public Function IsLoaded(formName As String) As Boolean
Dim frm As Object
For Each frm In VBA.UserForms
If frm.Name = formName Then
IsLoaded = True
Exit Function
End If
Next frm
IsLoaded = False
End Function
Then adjusted my above code like so
database_connect
Dim SQLStr As String
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Dim Counter As Long
If IsLoaded("Attendance") Then
SQLStr = "select distinct[Agentname] from dbo.[Attendance] Where [Team] ='" & attendance.Team.value & "'"
ElseIf IsLoaded("Reporting") Then
SQLStr = "select distinct[Agentname] from dbo.[Attendance] Where [Team] ='" & Reporting.Team.value & "'"
End If
If appconn.State = 0 Then
Call database_connect
End If
rs.Open SQLStr, appconn, adOpenStatic
With ctrl
Do
.AddItem rs![Agentname]
rs.MoveNext
Loop Until rs.EOF
End With
rs.Close
database_Disconnect
Set rs = Nothing
Exit Sub
now it works like a charm!

Related

How do I make the standard Access functions work after a connection to an external database?

The VBA code for external connection has been given to my by our IT-department. I did not wrote it myself. I just made some adjustments to make it work for my database. I am not an expert. The function Clear_Analysis just deletes all records from tabel tbl_Analysis.
The function Analysis_Check does work in all my other functions. I want to check if a table contains any records.
Function Analysis_Check()
If DCount("*", "tbl_Analysis") = 0 Then
MsgBox ("No Records!")
End If
If DCount("*", "tbl_Analysis") <> 0 Then
MsgBox ("Success!")
End If
End Function
But this function does not work anymore after a connection to an external SQL-database.
How do I make this work in the same function?
Function Analysis_LIMS()
Dim objRec
Dim objConn
Dim cmdString
Dim insertString
Call Clear_Analysis
Set objRec = CreateObject("ADODB.Recordset")
Set objConn = CreateObject("ADODB.Connection")
objConn.ConnectionString = "Provider=.....; "
objConn.Open
Set localDbConn = CreateObject("ADODB.Connection")
localDbConn.ConnectionString = "...;Persist Security Info=False;"
localDbConn.Open
cmdString = "SELECT DISTINCT t.rapportnaam, t.norm FROM taken t"
Set objRec = objConn.Execute(cmdString)
Do While Not objRec.EOF
insertString = "INSERT INTO tbl_Analysis ([Analysis], [Analysis_Norm]) VALUES ('" & objRec("rapportnaam") & "', '" & objRec("norm") & "')"
localDbConn.Execute (insertString)
objRec.MoveNext
Loop
Call Analysis_Check
localDbConn.Close
I want to add the call function Analysis_Check at the end of function Analysis_LIMS
I also tried to make Dcount as a seperate function and call this function at the end of function Analysis_LIMS
I can confirm that there are definately records in table tbl_Analysis.
But for both methods the Dcount function gives 0 as answer. This is not the case.
If I make a button on the same form which calls function Analysis_Check, then function Analysis_Check does work. But after that, if I call function Analysis_Check through function Analysis_LIMS the result is that I get popup message "No Records", I click OK, then comes a second popup message "Success".
If then I do the same thing again, but without using that temporary button it only gives the "No Records" aswer, but there are definately records in tbl_Analysis
I have no idea what I am doing wrong or why Access behaves like this. I guess it has something to do with the recordset? Maybe set the recordset to CurrentDb?
Any help would be appriciated.
Probably a timing issue as the query calls will run in another context.
Try either with DoEvents:
Do While Not objRec.EOF
insertString = "INSERT INTO tbl_Analysis ([Analysis], [Analysis_Norm]) VALUES ('" & objRec("rapportnaam") & "', '" & objRec("norm") & "')"
localDbConn.Execute (insertString)
objRec.MoveNext
Loop
DoEvents
or use DAO:
Dim Records As DAO.Recordset
Set Records = CurrentDb.OpenRecordset("Select * From tbl_Analysis", dbOpenDynaset, dbAppendOnly)
Do While Not objRec.EOF
Records.AddNew
Records!Analysis.Value = objRec("rapportnaam").Value
Records!Analysis_Norm.Value = objRec("norm").Value
Records.Update
objRec.MoveNext
Loop
Records.Close

MSAccess Form Search-Button conflicts with Edit-Button

I'm new to this forum and quite new to Access. I have the following problem. I've created an Form/Subform to edit the Data of a Query. Two Controls seem to be in conflict in my code.
"Search_Order" is an unbound text field. If text is entered and enter is pressed the corresponding fields of a query are shown. The code looks like the following:
Set rs_Search = Me.RecordsetClone
rs_Search.FindFirst "[OrderNumber]=""" & Search_Order & """"
If rs_Search.NoMatch Then
MsgBox "Sorry, no such record '" & Search_Order & "' was found.", _
vbOKOnly + vbInformation
Else
Me.Recordset.Bookmark = rs_Search.Bookmark
End If
rs_Search.Close
Search_Order = Null
Set rs_Search = Nothing
End Sub
The second command "ButtonSetOrderDetails10" should create a RecordsetClone of the Subform "sfrmChangeOrderDetails" and change the Value of the Field "OrderStatus" to the Vlaue of "10".
It has this code:
Private Sub ButtonSetOrderDetails10_Click()
Dim rs_Status_Change As DAO.Recordset
Set rs_Status_Change = Me.sfrmChangeOrderDetails.Form.RecordsetClone
With rs_Status_Change
Do While Not .EOF
.Edit
.Fields("OrderStatus") = 10
.Update
.MoveNext
Loop
End With
rs_Status_Change.Close
Set rs_Status_Change = Nothing
End Sub
I've looked both codes here up and modified them to the needs of my database. Both codes work fine so far, but unfortunately only once.
My problem is that as soon as I hit the Button "ButtonSetOrderDetails10" I can't do the same trick with a different order. I can search for the other order, it is displayed but the Button "ButtonSetOrderDetails10" does not work anymore. If I close the Form and reopen it, it works again.
It would be great if someone can give me a hint what I'm doing wrong here.
Best regards, Ferdi
I am surprised even works one time. With DAO recordset need to read dataset into memory before it will be able see records for edit otherwise just sees EOF and the loop doesn't run. Try:
rs_Status_Change.MoveLast
rs_Status_Change.MoveFirst
With rs_Status_Change
Don't even need to declare/set/close a recordset object.
Private Sub Search_Order_AfterUpdate()
With Me.RecordsetClone
.FindFirst "[OrderNumber]='" & Me.Search_Order & "'"
If .NoMatch Then
MsgBox "Sorry, no such record '" & Me.Search_Order & "' was found.", _
vbOKOnly + vbInformation
Else
Me.Bookmark = .Bookmark
End If
End With
Me.Search_Order = Null
End Sub
Private Sub ButtonSetOrderDetails10_Click()
With Me.sfrmChangeOrderDetails.Form.RecordsetClone
.MoveLast
.MoveFirst
Do While Not .EOF
.Edit
.Fields("OrderStatus") = 10
.Update
.MoveNext
Loop
End With
End Sub
Could really simplify code by running an UPDATE action SQL.
Private Sub ButtonSetOrderDetails10_Click()
CurrentDb.Execute "UPDATE ChangeOrderDetails SET OrderStatus=10 WHERE OrderNumber='" & Me.OrderNumber & "'"
End Sub

Access VBA Update Form Textbox With Sub Parameter

I'm having an issue with figuring out how to update my forms textbox with the value I ended with in the procedure. If a messagebox is used the output is fine. However, I want the user to be able to click the button and the textbox on that form be updated with the answer.
Private Sub btnTotalGuests_Click()
Call CalculateTotalGuestsForEachService
End Sub
Here is the procedure
Public Sub CalculateTotalGuestsForEachService()
'Declare variables
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim intTotalParty As Integer
Dim intID As Integer
'Set the current database
Set db = CurrentDb
'Set the recordset
intID = InputBox("Enter the Service ID (1-6)", "Service ID")
Set rst = db.OpenRecordset("Select Orders.* From Orders Where ServiceID =" & intID)
'Cycle through the records
Do While Not rst.EOF
If Not IsNull(rst!NoInParty) Then
intTotalParty = intTotalParty + rst!NoInParty
End If
rst.MoveNext
Loop
'Display total amount
txtTotalGuests.Text = intTotalParty 'Wondering how to display this in the textbox on the form.
'Close the recordset
rst.Close
Set rst = Nothing
Set db = Nothing
End Sub
Don't use Text property. You want Value property and since Value is default, don't even need to explicitly reference. Presume CalculateTotalGuestsForEachService is in the form module so can use Me.txtTotalGuests.
Consider domain aggregate function instead of looping recordset.
Dim intID As Integer
intID = InputBox("Enter the Service ID (1-6)", "Service ID")
Me.txtTotalGuests = DSum("NoInParty", "Order", "ServiceID =" & intID)

Excel VBA ADO SQL connection error - Could not find the object

I got a brilliant answer to my previous question from #Ryan Wildry but I thought I'd ask a different question regarding the same code: here goes.
Background Info
I have a shared (network/server) Excel template file which is both the input file and the data source (although on different sheets). Let's call that Input.xltm.
The code basically picks up a input in a range on Input Sheet, takes the first two letters and finds the closest code from Code Sheet, then populates a UserForm ListBox with the top five results.
The problem
The problem comes when users set off the UserForm and the error usually returns:
Run-time error '-2147467259'
The Microsoft Access database engine could not find the object 'C:\Users\user.name\Documents\Input1'. Make sure the object exists and that you spell its name and the path name correctly.......etc
I think it may have something to do with the fact Excel puts a number after the filename because it's a template file although I don't actually know!
The code
And here's the code:
Public MyConnection As New ADODB.Connection
Public MyRecordset As New ADODB.Recordset
Private Sub UserForm_Initialize()
Dim ColumnName As String: ColumnName = "[Variant code]"
Dim SearchStr As String: SearchStr = Left(Sheets("Input Sheet").Range("B4").Value2, 2)
Dim dbstring As String
dbstring = ThisWorkbook.FullName
Application.ScreenUpdating = False
If MyConnection.State <> adStateOpen Then
With MyConnection
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbstring & _
";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1';"
.Open
End With
End If
If MyRecordset.State = adStateOpen Then MyRecordset.Close
MyRecordset.Open "Select top 5 " & ColumnName & " from [Code Sheet$] where " & ColumnName & _
" like '%" & SearchStr & "%'", MyConnection, adOpenForwardOnly, adLockReadOnly
Me.ListBox1.Clear
If Not MyRecordset.EOF Then MyRecordset.MoveFirst
Application.ScreenUpdating = True
Do Until MyRecordset.EOF
Me.ListBox1.AddItem MyRecordset.Fields(0).Value
MyRecordset.MoveNext
Loop
End Sub
I just need everyone who accesses the file through the server to be able to pick up the correct data source (which is only in the next sheet) and populate the ListBox.
I'd be thankful for any suggestions! Thanks
#UPDATE
I have checked, now if you open (and then save) the actual template file so there's no '1' after the file name, then the code works as expected. It's only when the template is opened normally and the number automatically appended that it stops working.
It seems that you do not make early-binding for MyConnection and MyRecordset first.
You can make a late-binding by
step 1.
Change
Public MyConnection As New ADODB.Connection
Public MyRecordset As New ADODB.Recordset
to
Public MyConnection As object
Public MyRecordset As object
.
step 2.
Add
Set MyConnection = createobject("adodb.connection")
Set MyRecordset = createobject("adodb.recordset")
before If MyConnection.State <> adStateOpen Then

Userform Listbox populate and clear depending on selection from another listbox

I have 2 listboxes, lbA and lbB. I am populating lbA using SQL script which works fine. Now what i would like to do is when i select an item from lbA, lbB gets populated again from a SQL script. It works when selecting only one item from lbA but selecting two or more or unseleting an item then it either adds repeated items or doesnt delete items from lbB. I am puzzled as to how to approach this. Can anyone please help?
This is the code so far:
Private Sub lbA_Change()
Dim Num As Integer
Dim lngIndex As Long
If Me.lbA.ListIndex <> -1 Then
For lngIndex = 0 To lbA.ListCount - 1
If lbA.Selected(lngIndex) Then
Dim cnPubs As ADODB.Connection
Set cnPubs = New ADODB.Connection
Dim strConn As String
strConn = "PROVIDER=SQLOLEDB;"
strConn = strConn & "DATA SOURCE=MSSQLSERVER2008;INITIAL CATALOG=MyDB;"
strConn = strConn & " INTEGRATED SECURITY=sspi;"
cnPubs.Open strConn
Dim rsPubs As ADODB.Recordset
Set rsPubs = New ADODB.Recordset
With rsPubs
.ActiveConnection = cnPubs
.Open "My SQl Statement"
End With
If rsPubs.EOF Or rsPubs.BOF Then
Exit Sub
End If
rsPubs.MoveFirst
With Me.lbB
.Clear
Do
.AddItem rsPubs![strName]
rsPubs.MoveNext
Loop Until rsPubs.EOF
End With
rsPubs.Close
End If
Next
End If
End Sub
Try a function like this to get the SQL statement.
Function GetSQLFromListbox(lbx As MSForms.ListBox)
Dim i As Long
Dim sIn As String
If lbx.ListIndex <> -1 Then
sIn = " WHERE field IN("
For i = 0 To lbx.ListCount - 1
If lbx.Selected(i) Then
sIn = sIn & "'" & lbx.List(i) & "',"
End If
Next i
sIn = Left$(sIn, Len(sIn) - 1) & ")"
End If
GetSQLFromListbox = "SELECT * FROM table" & sIn
End Function
It should return something like
SELECT * FROM table WHERE field IN('2''3')
Then create a recordset from that statement and loop through it to fill the second listbox. Note that if nothing is selected, it returns the SQL without a WHERE clause, so you'd get everything. You might need to adjust that to suit your situation.