I have a vba that can send out multiple emails to vendors, but I would like to change it so it embeds the query and only sends one email per vendor. Here is what I have so far:
Option Compare Database
Public Sub SendFollowUpEmail()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim emailTo As String
Dim emailSubject As String
Dim emailText As String
Dim outApp As Outlook.Application
Dim outMail As Outlook.MailItem
Dim outlookStarted As Boolean
On Error Resume Next
Set outApp = GetObject(, "Outlook.Application")
On Error GoTo 0
If outApp Is Nothing Then
Set outApp = CreateObject("Outlook.Application")
outlookStarted = True
End If
Set db = CurrentDb
strSQL = "SELECT qry002UnmatchedOpenInvoices.kyUnique, qry002UnmatchedOpenInvoices.[Vendor Nbr],qry002UnmatchedOpenInvoices.[Vendor Name], " & _
" qry002UnmatchedOpenInvoices.[Purchasing Document], qry002UnmatchedOpenInvoices.Item,qry002UnmatchedOpenInvoices.[Document Date], " & _
" qry002UnmatchedOpenInvoices.Material, qry002UnmatchedOpenInvoices.[Short Text],qry002UnmatchedOpenInvoices.[Material Group], " & _
" qry002UnmatchedOpenInvoices.[Invoice Sent], qry002UnmatchedOpenInvoices.[Order Quantity],qry002UnmatchedOpenInvoices.[Order Unit], " & _
" qry002UnmatchedOpenInvoices.[Quantity in SKU], qry002UnmatchedOpenInvoices.[Stockkeeping unit],qry002UnmatchedOpenInvoices.[Net price], " & _
" qry002UnmatchedOpenInvoices.Currency, qry002UnmatchedOpenInvoices.[Price Unit],qry002UnmatchedOpenInvoices.[Release status], " & _
" qry002UnmatchedOpenInvoices.[No of Positions], tblVendors.Vendor, tblVendors.Email " & _
" FROM qry002UnmatchedOpenInvoices LEFT JOIN tblVendors ON qry002UnmatchedOpenInvoices.[Vendor Nbr] =tblVendors.[Vendor Number] " & _
" WHERE (((qry002UnmatchedOpenInvoices.Material) Is Null) AND ((qry002UnmatchedOpenInvoices.[Invoice Sent]) Is Null));"
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
Do Until rs.EOF
emailTo = Trim(rs.Fields("Email").Value & "; tom.nguyen#flocorp.com;mike.huston#flocorp.com")
emailSubject = "Open Invoices"
emailText = Trim("Please send invoices of the below Purchase Orders:") & vbCrLf
emailText = emailText & _
"PO# " & rs.Fields("[Purchasing Document]").Value
Set outMail = outApp.CreateItem(olMailItem)
outMail.To = emailTo
outMail.Subject = emailSubject
outMail.Body = emailText
outMail.Send
'rs.Edit
'rs("FUP_Date_Sent") = Now()
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
If outlookStarted Then
outApp.Quit
End If
Set outMail = Nothing
Set outApp = Nothing
End Sub
What you need to do is to use two recordsets. The first selects the distinct vendors, and the second selects the invoices for that vendor. Something like:
Sub sSendFollowUpEMail()
On Error GoTo E_Handle
Dim db As DAO.Database
Dim rsVendor As DAO.Recordset
Dim rsInvoice As DAO.Recordset
Dim objOL As New Outlook.Application
Dim objMail As Outlook.MailItem
Dim strSQL As String
Dim emailTo As String
Dim emailText As String
Set db = CurrentDb
strSQL = "SELECT DISTINCT V.[Vendor Number], V.EMail " _
& " FROM qry002UnmatchedOpenInvoices AS I LEFT JOIN tblVendors AS V ON I.[Vendor Nbr]=V.[Vendor Number] " _
& " WHERE I.Material IS NULL " _
& " AND I.[Invoice Sent] IS NULL;"
Set rsVendor = db.OpenRecordset(strSQL)
If Not (rsVendor.BOF And rsVendor.EOF) Then
Do
strSQL = "SELECT I.[Purchasing Document] " _
& " FROM qry2002UnMatchedOpenInvoices AS I " _
& " WHERE I.Material IS NULL " _
& " AND I.[Invoice Sent] IS NULL " _
& " AND I.[Vendor Nbr]=" & rsVendor("Vendor Number") _
& " ORDER BY I.[Purchasing Document] ASC;"
Set rsInvoice = db.OpenRecordset(strSQL)
If Not (rsInvoice.BOF And rsInvoice.EOF) Then
emailText = "Please pay:"
Do
emailText = emailText & vbCrLf & rsInvoice("Purchasing Document")
rsInvoice.MoveNext
Loop Until rsInvoice.EOF
End If
emailTo = rsVendor!EMail
Set objMail = objOL.CreateItem(olMailItem)
objMail.To = emailTo
objMail.Subject = EmailSubject
objMail.Body = emailText
objMail.Send
rsVendor.MoveNext
Loop Until rsVendor.EOF
End If
sExit:
On Error Resume Next
rsVendor.Close
rsInvoice.Close
Set rsVendor = Nothing
Set rsInvoice = Nothing
Set db = Nothing
Set objMail = Nothing
objOL.Quit
Set objOL = Nothing
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbcrfl & "sSendFollowUpEMail", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
A few notes.
In your original recordset you were including a whole load of fields that were not used in this procedure, which is not recommended - only get data that you need as this will enhance performance;
Secondly, it appears that you are mixing early and late binding of Outlook;
Finally, I've used aliases for the query/table names in the SQL statements - this makes the SQL more manageable, and also if you need to change one of the original tables/queries it is a lot easier to change the name just once.
Regards,
Related
I tested my code with static value
Set rs = CurrentDb.OpenRecordset("SELECT mail FROM UsersData WHERE depid = 2")
and it worked, but when I use the full statement
Set rs = CurrentDb.OpenRecordset( _
"SELECT mail FROM UsersData WHERE depid IN (SELECT depid FROM CyclesDefinitions WHERE cycledefid = " _
& Me.Combo135.Value & " AND rank = " & Me.Combo202.Value) & ")"
it generates an error i don't know what it means
(Compile Error: Type mismatch) and then nothing happens.
full code below: (everything works as intended and tested, but this line)
Private Sub Command15_Click()
Dim dbs As Database
Dim qdf As QueryDef
Set dbs = CurrentDb
Dim StrSqls As String
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT mail FROM UsersData WHERE depid IN (SELECT depid FROM CyclesDefinitions WHERE cycledefid = " & Me.Combo135.Value & " AND rank = " & Me.Combo202.Value) & ")"
'Set rs = CurrentDb.OpenRecordset("SELECT mail FROM UsersData WHERE depid = 2")
Dim ToMails As String
'Check is a flag on form to make sure record is not inserted more than once in Cycles Table
If Me.Check137.Value = False Then
DoCmd.RunCommand acCmdSaveRecord
dbs.Execute "INSERT INTO Cycles (scinvid, cycledefid) VALUES (" & Me.Combo200.Value & ", " & Me.Combo135.Value & ");"
dbs.Close
Me.Check137.Value = True
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst 'Unnecessary in this case, but still a good habit
Do Until rs.EOF = True
ToMails = rs(0) & ";" & ToMails
rs.MoveNext
Loop
Else
MsgBox "There are no Emails recorded for such department"
End If
rs.Close 'Close the recordset
Debug.Print ToMails
Set rs = Nothing 'Clean up
DoCmd.SendObject acSendNoObject, , , ToMails, , , "Test Subject", "Test Message", True
'objRecordset.Open ("SELECT depid FROM CyclesDefinitions WHERE cycledefid =" & Me.Combo135.Value & " AND cycleranktracking =" & Me.Combo202.Value)
'UserDepartmentID = DLookup("depid", "UsersData", "[username]= '" & fOSUserName & "'")
DoCmd.GoToRecord , , acNewRec
Me.Combo83.Requery
Combo83.RowSource = "SCINVSearch"
ElseIf Me.Check137.Value = True Then
DoCmd.GoToRecord , , acNewRec
Me.Combo83.Requery
Combo83.RowSource = "SCINVSearch"
End If
End Sub
In
Set rs = CurrentDb.OpenRecordset( _
"SELECT mail FROM UsersData WHERE depid IN (SELECT depid FROM CyclesDefinitions WHERE cycledefid = " _
& Me.Combo135.Value & " AND rank = " & Me.Combo202.Value) & ")"
You have placed the closing brace at the wrong place. It should be
Set rs = CurrentDb.OpenRecordset( _
"SELECT mail FROM UsersData WHERE depid IN (SELECT depid FROM CyclesDefinitions WHERE cycledefid = " _
& Me.Combo135.Value & " AND rank = " & Me.Combo202.Value & ")")
Your version tries to append a ")" to the Recordset instead of the SQL string. This generates the Type mismatch error.
old retired guy with passion for databases (Access 2016)
Please help with error. Have tried in vain to find solution.
Thanks to all who responded.
Please see "new" edited code below.
Thanks to everyone for your comments.
I am updating the code basis comments received and new info learned from other StackOverFlow post. But, I continue to have issues with making an error handling routing work?
'====This Code works Ok:
'................Except: for Error Handler???????
'================================================
Private Sub comBut_CatTotals_Click()
On Error GoTo EH
Dim rst As DAO.Recordset
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strSQL As String
Dim lonCatID() As Long
Dim lonCatTot() As Long
Dim i As Long
Dim t As Long
Dim iValue As Long
Dim tValue As Long
strSQL = "SELECT " & " qry_EventCategoryTotals_VBA_subquery.[CategoryName], Sum(tblWinnersItems.[Amount]) AS " & "CategoryTotals" & _
" FROM " & " qry_EventCategoryTotals_VBA_subquery" & _
" RIGHT " & " JOIN " & " tblWinnersItems" & " ON " & " qry_EventCategoryTotals_VBA_subquery.[ItemID] = tblWinnersItems.[ItemID] " & _
"GROUP" & " BY " & "qry_EventCategoryTotals_VBA_subquery.[CategoryName];"
'Debug.Print "strSQL: " & strSQL
'MsgBox strSQL
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", strSQL)
Set rst = qdf.OpenRecordset()
rst.MoveLast
If rst.RecordCount = 0 Then
MsgBox "No Winners recorded...Exiting", vbInformation
Exit Sub
End If
MsgBox "Number of records: " & rst.RecordCount
'intSize = rst.RecordCount
rst.MoveFirst
'... 6 ... records are shown ...
With rst
ReDim Preserve lonCatID(rst.RecordCount, 2)
ReDim Preserve lonCatTot(rst.RecordCount, 2)
Do While Not rst.EOF
i = 0
For i = i + 1 To rst.RecordCount - 1
lonCatID(1, 1) = rst.Fields(0)
iValue = lonCatID(1, 1)
Next i
t = 0
For t = t + 1 To rst.RecordCount - 1
lonCatTot(1, 2) = rst.Fields(1)
tValue = lonCatTot(1, 2)
Next t
rst.MoveNext
MsgBox " CategoryID = " & iValue & " Catagory Total = " & tValue, vbInformation, "Category Totals"
Loop
End With
MsgBox "Loop_Finished" '.....finishes OK
db.Close
Set rst = Nothing
Set qdf = Nothing
Set db = Nothing
Exit Sub
EH:
If Err.Number = 3021 Then
MsgBox "No Winners Entered...exiting", vbInformation
End If
MsgBox _
"There was an Error!" & vbCrLf & vbCrLf & _
"Number: " & Err.Number & vbCrLf & _
"Descriptionis: " & Err.Description, _
vbOKOnly + vbCritical, _
"Error!"
Exit Sub
End Sub
I am having and issue using update batch. I have a loop that goes through a recordset updating values. I have a minimum of 333 things in the batch. When it gets to the 254th item it bails. is there a limit to a batch.
On Error GoTo Err_cmdProcessAll
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim strTableName As String
Dim strSql As String
'
Set cn = New ADODB.Connection
cn.Open "Provider=sqloledb; " & _
"Data Source=" & "BLD-FS-SQLVS04\PRDINST4" & ";" & _
"Initial Catalog=" & "HNFS_NetProv" & ";" & _
"Integrated Security=SSPI;"
cn.CursorLocation = adUseServer
Dim strSortField As String
Dim additionalwhere As String
If cboValue = "pc3Claims" Then
strTableName = "Seq3_PendedClaims_Ranked"
strSortField = "DaysSinceReceivedClaim"
' additionalwhere = " AND (member_eligibility_ud Not Like '%Program%')
strSql = "Select * " & _
"FROM " & strTableName & _
" WHERE (Complete Is Null) And (AssignedTo Is Null)" & additionalwhere & _
" ORDER BY cast( " & strSortField & " as int )" & strSort
ElseIf cboValue = "pc3ContractAssignments" Then
strSortField = "date"
additionalwhere = ""
strSql = "Select * " & _
"FROM " & strTableName & _
" WHERE (Complete Is Null) And (AssignedTo Is Null)" & additionalwhere & _
" ORDER BY CONVERT(varchar(10), CONVERT(datetime, [" & strSortField & "], 111), 121) " & strSort
End If
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Source = strSql
.LockType = adLockOptimistic
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.Open
End With
'make change to above to include
Dim i As Long
Dim j As Long
Dim strAssignAssociate As String
Dim lngAllocAmt As Long
For i = 1 To ListView6.ListItems.Count
If ListView6.ListItems(i).Checked Then
strAssignAssociate = ListView6.ListItems(i).SubItems(1)
Debug.Print strAssignAssociate
lngAllocAmt = ListView6.ListItems(i).Text
For j = 1 To lngAllocAmt
Debug.Print rs.Fields("AssignedTo")
rs.Fields("AssignedTo") = strAssignAssociate
Debug.Print rs.Fields("AssignedTo")
rs.MoveNext
Next j
End If
Next i
rs.UpdateBatch
MsgBox "All Finished", vbOKOnly, "Inventory Control"
Set rs = Nothing
Set cn = Nothing
I found the problem. I am using a non-keyed file. I found that I had duplicates in the file. this has been rectified and the above code works fine.
Please help below code is not generating the mail and hangs access application:
Where is issue as when I dont do dQuery Processing Email Generates properly but dont include subform records aswell.
Without Subform Details Mail is something like this Email Generated with Proper variables present on MainForm
Private Sub InformCustomer_Click()
On Error GoTo Err_InformCustomer_Click
Dim CustName As String ' Customer Name
Dim varTo As Variant '-- Address for SendObject
Dim stText As String '-- E-mail text
Dim DelDate As Variant '-- Rec date for e-mail text
Dim stSubject As String '-- Subject line of e-mail
Dim stOrderID As String '-- The Order ID from form
Dim strSQL As String '-- Create SQL update statement
Dim errLoop As Error
Dim dQuery As String
Dim MyDb As DAO.Database
Dim rs As DAO.Recordset
stOrderID = Me![OdrID]
strSQL = "SELECT BrandName, ModelName, Status " _
& " FROM OrderProdDetails " _
& " WHERE (OrdID)=" & stOrderID & ";"
Set MyDb = CurrentDb
Set rs = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset)
While Not rs.EOF
dQuery = dQuery & rs![BrandName].Value & vbTab & rs![ModelName].Value & rs![Status].Value & vbCrLf
Wend
Set rs = Nothing
CustName = Me![CustName]
varTo = Me![CustEmail]
stSubject = ":: Update - Oder Status ::"
stOrderID = Me![OdrID]
DelDate = Me![OdrDeliveryDate]
stText = "Dear" & CustName & Chr$(13) & _
"You have been assigned a new ticket." & Chr$(13) & Chr$(13) & _
"Order Number: " & stOrderID & Chr$(13) & _
_
"Please refer to your order status " & Chr$(13) & _
"Exp Delevery Date: " & DelDate & Chr$(13) & Chr$(13) & _
dQuery & Chr$(13) & _
"This is an automated message. Please do not respond to this e-mail."
'Write the e-mail content for sending to assignee
DoCmd.SendObject , , acFormatTXT, varTo, , , stSubject, stText, True
MsgBox "Done"
Exit Sub
Err_InformCustomer_Click:
MsgBox Err.Description
End Sub
You have created an endless loop.
While Not rs.EOF
dQuery = dQuery & rs![BrandName].Value & vbTab & rs![ModelName].Value & rs![Status].Value & vbCrLf
' This is missing -->
rs.MoveNext
Wend
My form takes the data the user entered, constructs a SQL statement and returns the results. I would like to have a message box pop up when there are no matches found.
My current code/idea:
If qdf.sql = 0 Then
MsgBox "No clients matching your information." & _
vbCrLf & "have been found. Please try again." & _
, vbCritical, "No Matches"
Else
DoCmd.OpenForm "frmSearchResults"
Me.Visible = False
End If
I'm having trouble figuring out the correct syntax for if qdf.sql = 0 .
UPDATE: Full query
Private Sub cmdSearch_Click()
'On Error GoTo cmdSearch_Click_err
Dim db As Database
Dim strSQL As String
Dim rs As DAO.Recordset
Dim qdf As QueryDef
Dim strClientID As String
Dim strLastName As String
Dim strFirstName As String
Dim strDOB As String
Set db = CurrentDb
Set rs = db.OpenRecordset(qdf.sql)
' call QueryCheck module to determine if query exists
If Not QueryExists("qrySearch") Then
Set qdf = db.CreateQueryDef("qrySearch")
Else
Set qdf = db.QueryDefs("qrySearch")
End If
' handle nulls in the user's entries
If IsNull(Me.txtClientID.Value) Then
strClientID = " Like '*' "
Else
strClientID = "='" & Me.txtClientID.Value & "' "
End If
If IsNull(Me.txtLastName.Value) Then
strLastName = " Like '*' "
Else
strLastName = " Like '" & Me.txtLastName.Value & "*' "
End If
If IsNull(Me.txtFirstName.Value) Then
strFirstName = " Like '*' "
Else
strFirstName = " Like '*" & Me.txtFirstName.Value & "*' "
End If
If IsNull(Me.txtDOB.Value) Then
strDOB = " Like '*' "
Else
strDOB = "='" & Me.txtDOB.Value & "' "
End If
strSQL = "SELECT Clients.* " & _
"FROM Clients " & _
"WHERE Clients.clientid" & strClientID & _
"AND Clients.namelast" & strLastName & _
"AND Clients.namefirst" & strFirstName & _
"AND Clients.birthdate" & strDOB & _
"ORDER BY Clients.namelast,Clients.namefirst;"
Debug.Print strSQL
' check to see if the results form is open and close if it is
DoCmd.Echo False
If Application.SysCmd(acSysCmdGetObjectState, acForm, "frmSearchResults") = acObjStateOpen Then
DoCmd.Close acForm, "frmSearchResults"
End If
' run SQL statment
qdf.sql = strSQL
' check for no matches found
If rs.RecordCount = 0 Then
MsgBox "No clients matching your information were found." & _
vbCrLf & "Please search again.", vbInformation, "No Matches"
Else
DoCmd.OpenForm "frmSearchResults"
Me.Visible = False
End If
'cmdSearch_Click_exit:
' DoCmd.Echo True
' Set qdf = Nothing
' Set db = Nothing
'Exit Sub
'cmdSearch_Click_err:
' MsgBox "An unexpected error has occurred." & _
' vbCrLf & "Please note of the following details and contact the EIIS support desk:" & _
' vbCrLf & "Error Number: " & Err.Number & _
' vbCrLf & "Description: " & Err.Description _
' , vbCritical, "Error"
' Resume cmdSearch_Click_exit
End Sub
The reason that If qdf.sql = 0 then won't perform a proper check is that qdf contains the information about your query such as the SQL text that you are checking in that statement but not the results.
To get the results of the query you need to assign it to a Recordset after you have build your query. So first build your query and then assign it to the record set.
Dim db as DAO.Database
Set db = CurrentDb
Dim qdf as DAO.Querydef
Set qdf = db.CreateQueryDef("qrySearch")
Dim rs as DAO.Recordset
Set rs = CurrentDb.OpenRecordset(qdf.sql)
You can then check what your record set has returned.
If rs.RecordCount = 0 then
So where you have your line ' run SQL statment you would want to place the Set rs line.
If you have any ADO experience you can use something like
dim strSQL as String
dim conn as Connection
dim cmd as Command
dim rs as Recordset
(set up connection/command here)
cmd.commandtext = (your select query)
set rs = Command.execute
if rs.eof then
(or if rs.recordcount = 0 however returning a recordcount requires the correct cursortype - usually adOpenStatic - to be used)
'msgbox no match
else
'do stuff
If any of this is alien, then post your actual query and I'll try and give you the code in full. Good luck!