Assign Recordset to Variable in VBA - sql

I am trying to assign variables value from recordset and insert values into an Access table. I also need to clear the table and insert new set of data before inserting. The recordset is from a stored procedure in SQL Server. Following does not seem to work:
Dim conn As ADODB.Connection, cmd As ADODB.Command, rst As
ADODB.Recordset
Dim Itm As String, JobNo As Integer, RevNo As Integer, DUStatus As Date, LDUStatus As Date, UTrigger As String
Set conn = New ADODB.Connection
conn.ConnectionString = "Provider='sqloledb';Data Source=SERVER;Initial Catalog='Database';Integrated Security='SSPI';"
conn.Open
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = "rg_ItemsQuerySP"
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter("#JobNo", adInteger, adParamInput, , TempJobNo)
.Parameters.Append .CreateParameter("#RevNo", adInteger, adParamInput, , TempRevNo)
End With
Set rst = cmd.Execute
If rst.EOF Then Exit Function
rst.MoveLast
rst.MoveFirst
With rst
Do While Not .EOF
Itm = rst.Fields("Item")
JobNo = rst.Fields("Job No")
RevNo = rst.Fields("Revision No")
DUStatus = rst.Fields("DateUpdatedStatus")
LDUStatus = rst.Fields("LastDateUpdatedStatus")
UTrigger = rst.Fields("UpdateTrigger")
DoCmd.RunSQL ("INSERT INTO ItemsQuerySP_Temp values " & Itm & ", " & JobNo & ", " & RevNo & ", " & DUStatus & ", " & LDUStatus & ", " & UTrigger & ";")
rst.MoveNext
Loop
End With
conn.Close
Set conn = Nothing

Possibly your issue is the lack of quotes around string variables which would raise SQL error. Since you use ADO parameters, continue to use parameters via QueryDef, avoiding string concatenation (i.e., ampersands) or punctuation (i.e., quotes):
SQL (save below as an MS Access saved query, adjust types as needed: Text, Long, Double, etc.)
PARAMETERS PrmItm Text, PrmJobNo Text, PrmRevNo Text,
PrmDUStatus Text, PrmLDUStatus Text, PrmUTrigger Text;
INSERT INTO ItemsQuerySP_Temp
VALUES(PrmItm, PrmJobNo, PrmRevNo,
PrmDUStatus, PrmLDUStatus, PrmUTrigger)
VBA (relevant section)
Dim qdef AS QueryDef
' ... same as above...
Set qdef = CurrentDb.QueryDefs("mySavedQuery")
With rst
Do While Not .EOF
' BIND PARAMETERS
qdef!PrmItm = rst.Fields("Item")
qdef!PrmJobNo = rst.Fields("Job No")
qdef!PrmRevNo = rst.Fields("Revision No")
qdef!PrmDUStatus= rst.Fields("DateUpdatedStatus")
qdef!PrmLDUStatus = rst.Fields("LastDateUpdatedStatus")
qdef!PrmUTrigger = rst.Fields("UpdateTrigger")
' EXECUTE ACTION
qdef.Execute dbFailOnError
.MoveNext
Loop
End With
Set qdef = Nothing

Related

REPLACE data in Access table

I use VBA Word with Access, to create/store medical visit notes for Nursing homes.
The following is an example of how I get data out of Access (obviously picking up mid-Sub). This is populating a ComboBox in Word which gives me a list of all my patients, it is working great!
'....
Set Conn = New ADODB.Connection
Set rs = New ADODB.Recordset
strConn = ActiveDocument.CustomDocumentProperties("strConn").Value
Conn.Open (strConn)
qry = "SELECT * FROM tblPatientInfo ORDER BY LastName, Firstname"
rs.Open qry, Conn, adOpenKeyset
rs.MoveFirst
x = 0
While Not rs.EOF
F1.ComboDashPtList.AddItem
F1.ComboDashPtList.List(x, 0) = rs.Fields("LastName").Value & ""
F1.ComboDashPtList.List(x, 1) = rs.Fields("FirstName").Value & ""
F1.ComboDashPtList.List(x, 2) = Format(rs.Fields("DOB").Value, "MM\/dd\/yyyy") & ""
F1.ComboDashPtList.List(x, 3) = rs.Fields("MedNumber").Value & ""
rs.MoveNext
x = x + 1
Wend
rs.Close
Exit Sub`
'....
This is an example of how I send my data back to Access (again picking up mid-Sub).
` Set Conn = New ADODB.Connection
Set rs = New ADODB.Recordset
Conn.Open (strConn)
rs.Open strDBPtInfo, strConn, adOpenKeyset, adLockOptimistic, adCmdTable
rs.AddNew
rs!MedNumber = strMedNum
rs!LastName = strLastName
rs!Firstname = strFirstName
rs!DOB = dtDOB
rs.Update `
'....
Sometimes I need to completely overwrite or add to a specific field in a certain Access table. For years 'someone may have an allergy to penicillin, but suddenly they are also allergic to codeine, so that has to 'be updated. This is the approach I've taken but I keep getting an error:
'....
` Set Conn = New Connection
Set rs = New Recordset
Conn.Open (strConn)
strUpdateqry = "SELECT * FROM tblMedHxInfo WHERE MedNumber = " & Chr(34) & strMedNum & Chr(34) & ""
rs.Open strUpdateqry, strConn, adOpenKeyset
rs!Allergies = "Penicillin, Codeine"
rs.Update
If rs.State = 1 Then rs.Close
If Conn.State = 1 Then Conn.Close
Set rs = Nothing
Set Conn = Nothing`
....
This is the Error:
"Run-time error '3251': Current Recordset does not support updating.
This may ne a limitation of the provider, or of the selected locktype"
'Any help would be greatly appreciated!
'Thanks,
'Derek
'I've tried using the recordset to create a temporary table and then use that to update but it's getting over my head
Explicitly declare connection and recordset type. Then Set lines are not required.
Set the lock type argument.
Reference connection object not string variable for opening recordset.
Dim cn As ADODB.Connection, rs As ADODB.Recordset
cn.Open (strConn)
strUpdateqry = "SELECT * FROM tblMedHxInfo WHERE MedNumber = " & Chr(34) & strMedNum & Chr(34)
rs.Open strUpdateqry, cn, adOpenKeyset, adLockOptimistic
rs.Update "Allergies", "Penicillin, Codeine"
Or instead of opening recordset object for insert or update:
Dim cn As ADODB.Connection
cn.Open (strConn)
cn.Execute "UPDATE tblMedHxInfo SET Allergies = 'Penicillin, Codeine' WHERE MedNumber='" & strMedNum & "'"

VBA SQL query with WHERE clause

I'm trying to write VBA code to get SQL data into Excel. Everything works fine except the WHERE condition. I think the problem may be with quotation. This is my query:
Sub Engineering_Milestone()
Dim v_project As String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sql As String
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
v_project = Worksheets("Parameters").Range("B1").Value
'cn.Open "Provider = x.1; Data Source=x; Initial Catalog=x; Integrated Security=x"
cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"
Worksheets("Engineering_Milestone").Range("A2:G5000").ClearContents
sql = " SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, A.MILESTONE, A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE FROM X as A Inner Join X as B on A.ENGINEER_ID = B.ENGINEER_ID WHERE B.Project_ID = " & "'" & v_project & "'" and A.Project_ID = " & "'" & v_project & "'"
rs.Open sql, cn
Sheets("Engineering_Milestone").Cells(2, 1).CopyFromRecordset rs
rs.Close
cn.Close
End Sub
It works fine when the SQL query has one condition i.e ...where B.Project_ID = " & "'" & v_project & "'" (without second condition -> and A.Project_ID = " & "'" & v_project & "'").
I'm very new to this so would be grateful if anyone can help...Many thanks.
As I said never write SQL code by string concatenation, use parameters. After seeing your code it is now a little bit easier:
Sub Engineering_Milestone()
Dim v_project As String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sql As String
Dim cmd as ADODB.Command
Set cn = New ADODB.Connection
v_project = Worksheets("Parameters").Range("B1").Value
'cn.Open "Provider = x.1; Data Source=x; Initial Catalog=x; Integrated Security=x"
cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"
Worksheets("Engineering_Milestone").Range("A2:G5000").ClearContents
sql = "SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, " & _
" A.MILESTONE, A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE" & _
" FROM X as A" & _
" Inner Join X as B " & _
" on A.ENGINEER_ID = B.ENGINEER_ID and B.Project_ID = A.Project_ID" & _
" WHERE B.Project_ID = ?"
set cmd = New ADODB.Command
cmd.ActiveConnection = cn
cmd.CommandText = sql
cmd.Parameters.Append cmd.CreateParameter("#projectId", adVarchar)
cmd.Parameters("#projectId").Value = v_project
Set rs = cmd.Execute()
Sheets("Engineering_Milestone").Cells(2, 1).CopyFromRecordset rs
rs.Close
cn.Close
End Sub
NOTE: Your SQL is really vague. You are doing a self join just to create some kind of cartesian join? Probably in fact engineerId, projectId combinations are unique. If that is correct than you could simplify your SQL:
sql = "SELECT ENGINEER_ID, [Description], BUDGET_APPROVED, " & _
" MILESTONE, [DESCRIPTION], PCT_COMPLETE, SCHEDULE_DATE" & _
" FROM X" & _
" WHERE Project_ID = ?"
You only provided a half of one line of code so I'm can only guess that this is what you're trying for:
"where B.Project_ID = '"& v_project &"'& And A.Project_ID = ' & v_project "'"
Strings can be confusing when entering/exiting multiple types of quotes, but when you're troubleshooting a problem building a string, start be remove all the variables and just using a hard-coded SQL string.
Once that's working, start replacing the values with variables (and appropriate quotes) one at a time.
Consider SQL parameterization, the industry best practice when passing values into SQL queries -not just in VBA or your database but across all langauge interfaces to any databases. This process is more readable and maintainable as you no longer worry about quotes. Plus, code (SQL query) is separated from data (VBA variables).
Using ADO, parameters can be defined and set using the Command Object.
Dim v_project As String, sql As String
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim cmd As New ADODB.Command
v_project = Worksheets("Parameters").Range("B1").Value
cn.Open "Provider = Sx; Data Source=x; Initial Catalog=x; Integrated Security=x"
' PREPARED STATEMENT WITH QMARK PLACEHOLDERS
sql = "SELECT A.ENGINEER_ID, B.[Description], B.BUDGET_APPROVED, A.MILESTONE," _
& " A.[DESCRIPTION], A.PCT_COMPLETE, A.SCHEDULE_DATE" _
& " FROM X AS A INNER JOIN X as B ON A.ENGINEER_ID = B.ENGINEER_ID" _
& " WHERE B.Project_ID = ? AND A.Project_ID = ?"
' COMMAND OBJECT
Set cmd = New ADODB.Connection
With cmd
.ActiveConnection = cn ' CONNECTION OBJECT
.CommandText = sql
.CommandType = adCmdText
' BINDING PARAMETERS
.Parameters.Append .CreateParameter("a_projid", adVarChar, adParamInput, , v_project)
.Parameters.Append .CreateParameter("b_projid", adVarChar, adParamInput, , v_project)
End With
' ASSIGN TO RECORDSET
Set rs = cmd.Execute
With Worksheets("Engineering_Milestone")
.Range("A2:G5000").ClearContents
.Cells(2, 1).CopyFromRecordset rs
End With
rs.Close: cn.Close
Set cmd = Nothing: Set rs = Nothing: Set cn = Nothing
Never write SQL code like that concatenating strings. Instead simply use parameters. ie: (say vProject is integer)
.. where B.Project_ID = ? And A.Project_ID = ?
cmd.Parameters.Append .CreateParameter("#projectId", adInteger, adParamInput, 0, vProject)
cmd.Parameters.Append .CreateParameter("#projectId", adInteger, adParamInput, 0, vProject)
Note: cmd is your ADODB.Command object that you use for your command.

Pass a value dynamically to SQL Server through VBA

Disclaimer: I am new to VBA.
I hope to pass the value in the SQL query (30881570) through a field on my Excel sheet. I have tried a few different things.
Private Sub cmdImport_Click()
Call cmdClear_Click
Dim conn As New ADODB.Connection, cmd As New ADODB.Command, rs As New ADODB.Recordset
With conn
.ConnectionString = _
"Provider=SQLOLEDB; " & _
"Data Source=PRGTAPPDBSWC019; " & _
"Initial Catalog=DETEP;" & _
"Integrated Security=SSPI;"
.Open
End With
With cmd
.ActiveConnection = conn
.CommandText = "SELECT * FROM [dbo].[tbl_PMHeader] WHERE [PMHeader_PM_NUM] = '30881570'"
.CommandType = adCmdText
End With
Set rs.Source = cmd
rs.Open
'Need this to populate header row, starting at specified Range
For intColIndex = 0 To rs.Fields.Count - 1
Range("B1").Offset(0, intColIndex).Value = rs.Fields(intColIndex).Name
Next
'This is where your data table will be copied to
ActiveSheet.Range("B2").CopyFromRecordset rs
Worksheets("Sheet1").Columns("B:BB").AutoFit
Worksheets("Sheet1").Range("A25").Formula = "=COUNTA(B:B)-1"
End Sub
It looks like you're already passing that value as criteria for the query's WHERE statement.
If you're asking how to replace that with a value from a worksheet, here's one way:
.CommandText = "SELECT * FROM [dbo].[tbl_PMHeader] " & _
"WHERE [PMHeader_PM_NUM] = '" & Sheets("mySheet").Range("A1") & "'"
...where your worksheet is named mySheet and the value is in cell A1.
This is the simplest method, potentially fine for internal use by trusted parties, but if the value has any ' single-quotes in it, you will get an error.
Worst-case scenario, this method leaves you open to SQL Injection attacks. Depends on your needs (and whether this this is just a school assignment), you may be better of using a parameter query.
See Also:
MSDN Blog : How and Why to Use Parameterized Queries
MSDN Blog : Everything About Using Parameters from Code
Private Sub cmdImport_Click()
Dim conn As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim sqlStr As String
With conn
.ConnectionString = _
"Provider=SQLOLEDB; " & _
"Data Source=PRGTAPPDBSWC019; " & _
"Initial Catalog=DETEP;" & _
"Integrated Security=SSPI;"
.Open
End With
orderno = Sheets("Sheet1").Range("A22")
strSql = "SELECT * FROM [dbo].[tbl_PMHeader] " & _
"WHERE [PMHeader_PM_NUM] = " & orderno
With cmd
.ActiveConnection = conn
.CommandText = strSql
.CommandType = adCmdText
End With
'Call cmdClear_Click
Set rs.Source = cmd
rs.Open
'Need this to populate header row, starting at specified Range
For intColIndex = 0 To rs.Fields.Count - 1
Range("B1").Offset(0, intColIndex).Value = rs.Fields(intColIndex).Name
Next
'This is where your data table will be copied to
ActiveSheet.Range("B2").CopyFromRecordset rs
Worksheets("Sheet1").Columns("B:BB").AutoFit
Worksheets("Sheet1").Range("A25").Formula = "=COUNTA(B:B)-1"
End Sub

Pass VBA Variable into Access Query(Excel VBA)

Im new at trying to construct queries out of vba. I am trying to figure out how to pass a variable inside the VBA syntax. Mind showing me where im dumb?
I tried this below but there's an automation error that pops up. Ive noticed from playing aroudn that automation errors come up when youve just got syntax wrong, so hopefully its something small?
Any help is greatly appreciated
Sub GetDataFromAccess()
Dim cmd As New ADODB.Command, rs As ADODB.Recordset
Dim recordNum As Integer
recordNum = 7
cmd.ActiveConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Ashleysaurus\Desktop" & "\" & "xyzmanu3.accdb"
cmd.CommandType = adCmdText
cmd.CommandText = "SELECT * FROM Invoice WHERE OrderNumber <" & "'" & recordNum & "'" & "ORDER BY OrderNumber ASC"
Set rs = cmd.Execute
Sheet1.Range("A2").CopyFromRecordset rs
rs.Close
cmd.ActiveConnection.Close
Debug.Print "Done!"
End Sub
While learning to build VBA queries, consider parameterized queries and avoid any need of quotes! This is an industry best practice across all languages when passing values in dynamic SQL queries.
Sub GetDataFromAccess()
Dim cmd As New ADODB.Command, rs As ADODB.Recordset
Dim recordNum As Integer
recordNum = 7
With cmd
.ActiveConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source=C:\Users\Ashleysaurus\Desktop" & "\" & "xyzmanu3.accdb"
.CommandType = adCmdText
.CommandText = "SELECT * FROM Invoice" _
& " WHERE OrderNumber < ? ORDER BY OrderNumber ASC"
End With
cmd.Parameters.Append cmd.CreateParameter("recordNumParam", adInteger, adParamInput, 10)
cmd.Parameters(0).Value = recordNum
Set rs = cmd.Execute
Sheet1.Range("A2").CopyFromRecordset rs
rs.Close
cmd.ActiveConnection.Close
Debug.Print "Done!"
End Sub
Assuming OrderNumber is a number, do not use quotes.
Also make sure you have a space before Order By:
cmd.CommandText = "SELECT * FROM Invoice WHERE OrderNumber <" & recordNum & " ORDER BY OrderNumber ASC"

Unable to View Recordsets in Access Form Listbox using NextRecordset

I’m using the NEXTRECORDSET method to view the records generated from a SQL stored procedure. The SP takes the user input and searches 3 tables in a SQL database and returns those records which contain the value(s) to Access. I'm able to successfully see the results in my debug (debug.print) window in Access, but not in the Listbox lstResults1 or all 3 listboxes of an Access form. The form procedure that calls the function and the function itself is below. I was able to successfully pass the resultset to the Listboxes (lstResults1, lstResults2, etc.) in the form by substituting the rstCompound statement in the Function with a loop for each Recordset (see third code sample) but it wasn't as clean and I was getting an "Object Variable or With Block Variable Not Set", every time one of the values I searched for was in the second or third tables:
PROCEDURE
Private Sub cmdRun_Click()
'On Error Resume Next
Dim strSQL As String
'Stored procedure + parameters called from form
strSQL = "Exec spSQL_SearchDatabase " & "'" & Me.txtTables & "'" & _
", " & "'%" & Me.txtSearchTerm & "%'"
OpenMyRecordset rstCompound, strSQL
Set Me.lstResults1.Recordset = rstCompound
'debug - view procedure
Me.lblQuery.Caption = strSQL
Me.Repaint
End Sub
FUNCTION
Public Function OpenMyRecordset(rstCompound As ADODB.Recordset, strSQL As String, _
Optional rrCursor As rrCursorType, _
Optional rrLock As rrLockType, Optional bolClientSide As Boolean) As ADODB.Recordset
If con.STATE = adStateClosed Then
con.ConnectionString = "ODBC;Driver={SQL Server};Server=vnysql;DSN=RecordsMgmt_SQLDB;UID=DMP;Trusted_Connection=Yes;DATABASE=RecordsManagementDB;"
con.Open
End If
Set rstCompound = New ADODB.Recordset
With rstCompound
.ActiveConnection = con
.CursorLocation = adUseClient
.CursorType = IIf((rrCursor = 0), adOpenDynamic, rrCursor)
.LockType = IIf((rrLock = 0), adLockOptimistic, rrLock)
.Open strSQL
End With
' Display results from each recordset
intCount = 1
Do Until rstCompound Is Nothing
Debug.Print "Contents of recordset #" & intCount
Do Until rstCompound.EOF
Debug.Print rstCompound.Fields(0), rstCompound.Fields(1)
rstCompound.MoveNext
Loop
Set rstCompound = rstCompound.NextRecordset
intCount = intCount + 1
Loop
End Function
Substituted Statement in Function
Set rs1 = New ADODB.Recordset
With rs1
.ActiveConnection = con
.CursorLocation = adUseClient
.CursorType = IIf((rrCursor = 0), adOpenDynamic, rrCursor)
.LockType = IIf((rrLock = 0), adLockOptimistic, rrLock)
.Open strSQL
End With
Do Until rs1.EOF
Debug.Print rs1.Fields(0), rs1.Fields(1)
rs1.MoveNext
Loop
Set rs2 = rs1.NextRecordset
Do Until rs1.EOF
Debug.Print rs2.Fields(0), rs2.Fields(1)
rs2.MoveNext
Loop
Set rs3 = rs2.NextRecordset
Do Until rs3.EOF
Debug.Print rs3.Fields(0), rs3.Fields(1)
rs3.MoveNext
Loop
The Function OpenMyRecordset never sets anything to return. It needs something like
Set OpenMyRecordset = rstCompound
Also, with all the debug statements rstCompound may be at EOF and have nothing to show.