Run time error '91' when using MSSql - sql-server

I'm making a program in which I have to check some column values in another table before trying to save values in a different table.. both tables are in SQL.
I tried my best to do it myself but I get the error near the highlighted line.
rs.open(insert into testreport_tb1...
Private Sub Command1_Click()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim BrdSrNo As String
Dim Result As Boolean
Dim machineName As String
machineName = Environ("computername")
' Ready objects for use.
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
BrdSrNo = BoardSrNo.Text
Result = False
' Connect.
cn.Open "{Here I give the connection string}"
' Fetch a recordset.
rs.Open "select * from testreport_tb1 where board_SrNo = '" & BrdSrNo & "' order by test_DateTime desc", cn, adOpenStatic, adLockReadOnly
' Display value, and total recordcount.
MsgBox rs.Fields(3)
MsgBox rs.Fields(8)
'MsgBox rs.RecordCount
stage_Status = rs.Fields(3)
stage_Id = rs.Fields(8)
rs.Close
cn.Close
If stage_Status = "C" Then
If stage_Id = "True" Then
rs.Open "insert into testreport_tb1 values('" & BrdSrNo & "',3,GETDATE(),'" & Result & "',NULL,'" & machineName & "',' KO ','A','D')", cn, adOpenDynamic, adLockBatchOptimistic
MsgBox "saved"
End If
End If
' Close and release objects.
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
End Sub

As far as I remember, you can't use rs.Open when executing DML statements, (insert, update or delete), but only when you are executing select statements.
Also, you need to use ADODB.Command and set parameters instead of concatenating strings to create your insert statement, otherwise it's an open door for sql injection attacks.
It's been a very long time since the last time I've worked with ADODB, but your insert code should look something like this:
If stage_Status = "C" And stage_Id = "True" Then
Dim cmd as new ADODB.Command
cmd.CommandText = "insert into testreport_tb1 values(?, 3, GETDATE(), ?, NULL, ?, ' KO ', 'A', 'D')"
cmd.ActiveConnection = cn
Set param = cmd.CreateParameter(, adVarChar, adParamInput)
param.Value = BrdSrNo
cmd.Parameters.Append param
Set param = cmd.CreateParameter(, adVarChar, adParamInput)
param.Value = Result
cmd.Parameters.Append param
Set param = cmd.CreateParameter(, adVarChar, adParamInput)
param.Value = machineName
cmd.Parameters.Append param
cmd.Execute
MsgBox "saved"
End If
Note: Code was written directly here, and as I wrote, it's been a long time since I've used ADODB, so there might be mistakes in the code. However, this is the proper way of executing an insert statement with ADODB.

Related

Can't execute SQL Server stored procedure in Access module

In Access I created a form with Text1, List1, and Command1 elements.
The code for command button is:
Private Sub Command1_Click()
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Set con = New ADODB.Connection
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
con.Open "Provider=sqloledb;Data Source=192.168.100.41,1433;Network Library=DBMSSOCN;Initial Catalog=xxx;User ID=xxx;Password=xxx;"
cmd.ActiveConnection = con
cmd.CommandTimeout = 0
cmd.Parameters.Append cmd.CreateParameter("#keyword", adVarChar, adParamInput, 100, Trim(Text1.Value))
cmd.CommandText = "stored_procedure"
Set rs = cmd.Execute(, , adCmdStoredProc)
If (rs.RecordCount <> 0) Then
Do While Not rs.EOF
Me.List1.AddItem (rs.Fields(0).Value & " | " & rs.Fields(1).Value & " | " & rs.Fields(2).Value)
rs.MoveNext
Loop
End If
rs.Close
Set rs = Nothing
Set cmd = Nothing
con.Close
Set con = Nothing
End Sub
When I try to run the code, nothing happens. No error. Seems like button is empty.
The SP works fine in SQL server.
The same button code, works fine in Excel form.
If I replace SP part with [rs.open "select * from table where keyword like.."] works fine
Thank you
You probably need to use a client side cursor, I would debug.print rs.RecordCount to check what it thinks are the returned records.
conn.cursorlocation=aduseclient

passing recordset to stored procedure in MS access

So, I am currently working on an app where I need to call a stored procedure that takes a User defined table as a parameter. In .NET I am able to just pass the data in a datatable, but in MS Access VBA I am having difficulty passing an ADO recordset to the stored procedure as the user defined table.
Private Sub DeleteRecords()
On Error GoTo Err_DeleteRecords
Dim cnn As ADODB.Connection, cmd As New ADODB.Command, param As New ADODB.Parameter
Dim i As Integer
Dim rs As ADODB.Recordset
Dim text As String
Dim gs As String
Set cnn = CurrentProject.Connection
gs = "DECLARE #StagingRecsToDelete StagingRecsToDelete_UDT; SELECT * FROM #StagingRecsToDelete"
Set rs = New ADODB.Recordset
rs.Open gs, cnn, adOpenKeyset, adLockOptimistic
If rs.RecordCount = 0 Then
For i = 0 To Me.lstFingerPrintServiceStaging.ListCount - 1
If Me.lstFingerPrintServiceStaging.Selected(i) Then
text = text + Me.lstFingerPrintServiceStaging.Column(0, i)
rs.AddNew
rs!intFingerPrintServiceStagingID = text
End If
Next i
End If
If rs.RecordCount > 0 Then
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "dbo.SPFingerPrintDeleteErrors"
Set param = cmd.CreateParameter("#ReturnValue", adInteger, adParamReturnValue)
cmd.Parameters.Append param
Set param = cmd.CreateParameter("StagingRecsToDelete_UDT", adVarient, adParamInput, , rs)
cmd.Parameters.Append param
Set param = cmd.CreateParameter("#ErrNbr", adInteger, adParamOutput)
cmd.Parameters.Append param
Set param = cmd.CreateParameter("#ErrMsg", adVarChar, adParamOutput, 8000)
cmd.Parameters.Append param
cmd.Execute
End If
Select Case cmd.Parameters("#ReturnValue").Value
Case 1 'System error
MsgBox cmd.Parameters("#ErrMsg").Value, vbOKOnly + vbInformation, gApplicationTitle
Exit Sub
Case 0 'Succeeds
MsgBox "The Selected records have been successfully deleted.", vbOKOnly + vbInformation, gApplicationTitle
Case -1 'User Error
MsgBox cmd.Parameters("#ErrMsg").Value, vbOKOnly + vbInformation, gApplicationTitle
Exit Sub
End Select
cnn.Close
Set cnn = Nothing
Exit_DeleteRecords:
Exit Sub
Err_DeleteRecords:
MsgBox "Form=" & Me.Name & ", Function=DeleteRecords" & vbCrLf & "Err#=" &
Err & " " & Error$
Resume Exit_DeleteRecords
End Sub
For the most part, all of it works, but I do not know what datatype to set the UDT to when I pass it to the stored procedure.
The MS Access (DAO) does not support it.
You can create an XML with your data and pass it as SP param or insert it into a temporary table one by one fisrt.

Classic Asp Secure Insert Statement Form to Database

I have an online form, data from there needs to be entered into a MSSQL database. I'm trying to create a secure insert statement. With the following code I get this error.
Microsoft OLE DB Provider for SQL Server error '80040e5d'
Parameter name is unrecognized.
<%#language="vbscript" codepage="65001" %>
<% option explicit %>
Dim Form_Name
Dim Form_Email
Form_Name= ProtectSQL(request.Form("Name"))
Form_Email= ProtectSQL(Request.Form("Email"))
Dim objConn
set objConn = Server.CreateObject("ADODB.Connection")
Dim strConn
strConn="provider=SQLOLEDB;Server=localhost;Database=dbname;Uid=username;Pwd=password;"
objConn.open strConn
Dim DateSubmitted
DateSubmitted=now()
Dim strSQL
strSQL = "INSERT INTO tablename(DateSubmitted, Name, Email) VALUES('" & DateSubmitted & "', ?, ?)"
Dim objCmd
set objCmd = Server.Createobject("ADODB.Command")
objCmd.ActiveConnection = objConn
objCmd.CommandText = strSQL
objCmd.CommandType = adCmdText
objCmd.NamedParameters = true
Dim objParam1
Set objParam1 = objCmd.CreateParameter("Name", adVarChar, adParamInput, Len(Form_Name), Form_Name)
objCmd.Parameters.Append objParam1
Dim objparam2
Set objparam2 = objCmd.CreateParameter("Email", adVarChar, adParamInput, Len(Form_Email), Form_Email)
objCmd.Parameters.Append objparam2
objCmd.Execute, , adCmdText And adExecuteNoRecords
objConn.close
Set objConn = Nothing
I have also tried
strSQL = "INSERT into tablename(DateSubmitted,Name,Email)values('" & DateSubmitted & "',#Name,#Email)"
objCmd.Parameters.Append objCmd.CreateParameter("#Name",adVarChar,adParamInput,100,Form_Name)
objCmd.Parameters.Append objCmd.CreateParameter("#Email",adVarChar,adParamInput,100,Form_Email)
With this I get Must declare the scalar variable "#Name".
Both error messages reference the objCmd.Execute line
Is there a better way to do an insert statement? I don't need a recordset with this.
You have 5 placeholders in
strSQL = "INSERT INTO tablename(DateSubmitted, Name, Email) VALUES('" & DateSubmitted & "', ?, ?, ?, ?, ?)"
but add only 2 parameters.
I use code like the following code to perform parameterized queries in classic asp:
public sub sql_execute(sql, parameterArray)
dim cnx
Set cnx=CreateObject("ADODB.Connection")
cnx.Open wfDataConnection
if isArray(parameterArray) then
dim cmd, i
Set cmd = CreateObject("ADODB.Command")
With cmd
.CommandText = sql
.CommandType = adCmdText
.ActiveConnection = cnx
for each i in parameterArray
.Parameters.Append .CreateParameter(i(0), i(1), i(2), i(3), i(4))
next
end with
cmd.execute rowsAffected, , adExecuteNoRecords
else
cnx.execute sql, rowsAffected, adExecuteNoRecords
end if
end sub
Calling it like so:
dim sql, parameterArray
sql = "INSERT INTO table (val1, val2) VALUES (?, ?)"
paramaterArray = Array(_
Array("#p1", adInteger, adParamInput, , val1)_
, Array("#p2", adVarChar, adParamInput, 255, val2)_
)
sql_execute sql, parameterArray
I'm not too sure about the variable names (#p1, #p2, etc) when creating parameters. It doesn't seem to matter what you call the variables, but they do require some kind of name in order for it to work.

How to return values from a SQL Server Stored Procedure and Utilise them in Access VBA

I've set up a Stored Procedure in SQL Server that works fine. I can now call it from VBA, but want to return a value to know if there were any errors etc. The last parameter in my SP is set up as OUTPUT:
#DataSetID int = 0,
#Destination char(1)='-',
#errStatusOK bit OUTPUT
My VBA to call the SP is below, but it won't work now, after adding the new parameter and I'm not sure where I'm going wrong, I keep getting 3708 - Parameter object is improperly defined. Inconsistent or incomplete information was provided.:
Set cnn = New adodb.Connection
cnn.ConnectionString =
"DRIVER=SQL Server;SERVER=SERVER\SERVER;DATABASE=a_db;Trusted_Connection=Yes"
cnn.Open cnn.ConnectionString
Set cmd = New adodb.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "stprMoveDataSet"
Set param = cmd.CreateParameter
("#DataSetID", adInteger, adParamInput, , stDataSet)
cmd.Parameters.Append param
Set param = cmd.CreateParameter
("#Destination", adChar, adParamInput, 1, stDestination)
cmd.Parameters.Append param
Set param = cmd.CreateParameter
("#errStatusOK", adBit, adParamReturnValue)
cmd.Parameters.Append param
rs.CursorType = adOpenStatic
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
rs.Open cmd
How can I get the vba to work with the OUTPUT parameter and make the return value 'readable' by the vba.
EDIT - I've changed the question to be more specifically about returning values and not just about using OUTPUT Parameters.
Several ways are possible to get values back using VBA.
Recordset
Count of records affected (only for Insert/Update/Delete otherwise -1)
Output parameter
Return value
My code demonstrates all four. Here is a stored procedure that returns a value:
Create PROCEDURE CheckExpedite
#InputX varchar(10),
#InputY int,
#HasExpedite int out
AS
BEGIN
Select #HasExpedite = 9 from <Table>
where Column2 = #InputX and Column3 = #InputY
If #HasExpedite = 9
Return 2
Else
Return 3
End
Here is the sub I use in Excel VBA. You'll need reference to Microsoft ActiveX Data Objects 2.8 Library.
Sub CheckValue()
Dim InputX As String: InputX = "6000"
Dim InputY As Integer: InputY = 2014
'open connnection
Dim ACon As New Connection
'ACon.Open ("Provider=SQLOLEDB;Data Source=<SqlServer>;" & _
' "Initial Catalog=<Table>;Integrated Security=SSPI")
'set command
Dim ACmd As New Command
Set ACmd.ActiveConnection = ACon
ACmd.CommandText = "CheckExpedite"
ACmd.CommandType = adCmdStoredProc
'Return value must be first parameter else you'll get error from too many parameters
'Procedure or function "Name" has too many arguments specified.
ACmd.Parameters.Append ACmd.CreateParameter("ReturnValue", adInteger, adParamReturnValue)
ACmd.Parameters.Append ACmd.CreateParameter("InputX", adVarChar, adParamInput, 10, InputX)
ACmd.Parameters.Append ACmd.CreateParameter("InputY", adInteger, adParamInput, 6, InputY)
ACmd.Parameters.Append ACmd.CreateParameter("HasExpedite", adInteger, adParamOutput)
Dim RS As Recordset
Dim RecordsAffected As Long
'execute query that returns value
Call ACmd.Execute(RecordsAffected:=RecordsAffected, Options:=adExecuteNoRecords)
'execute query that returns recordset
'Set RS = ACmd.Execute(RecordsAffected:=RecordsAffected)
'get records affected, return value and output parameter
Debug.Print "Records affected: " & RecordsAffected
Debug.Print "Return value: " & ACmd.Parameters("ReturnValue")
Debug.Print "Output param: " & ACmd.Parameters("HasExpedite")
'use record set here
'...
'close
If Not RS Is Nothing Then RS.Close
ACon.Close
End Sub
Set cnn = New adodb.Connection
cnn.ConnectionString =
"DRIVER=SQL Server;SERVER=SERVER\SERVER;DATABASE=a_db;Trusted_Connection=Yes"
cnn.Open cnn.ConnectionString
Set cmd = New adodb.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "stprMoveDataSet"
Set param1 = cmd.CreateParameter
("#DataSetID", adInteger, adParamInput, , stDataSet)
cmd.Parameters.Append param
Set param2 = cmd.CreateParameter
("#Destination", adChar, adParamInput, 1, stDestination)
cmd.Parameters.Append param
Set param3 = cmd.CreateParameter
("#errStatusOK", adBit, adParamOutput, , adParamReturnValue)
cmd.Parameters.Append param
rs.CursorType = adOpenStatic
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
rs.Open cmd
I'd initially looked at OUTPUT Parameters, but could not find out how to get them back to Access (in VBA) to then provide feedback to the user. A colleague suggested using a SELECT in the Stored procedure and to use this.
STORED PROCEDURE:
Added the following at the end:
SELECT #errStatusOK as errStatusOK, #countCurrent as countCurrent, #countHistorical as countHistorical
VBA:
Dim cnn As ADODB.Connection
Dim cmd As New ADODB.Command, rs As New ADODB.Recordset, param As New ADODB.Parameter
Dim fld As ADODB.Field
Dim stMessage As String
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DRIVER=SQL Server;SERVER=SERVER\SERVER;DATABASE=a_db;Trusted_Connection=Yes"
cnn.Open cnn.ConnectionString
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "stprMoveDataSet"
Set param = cmd.CreateParameter("#DataSetID", adInteger, adParamInput, , stDataSet)
cmd.Parameters.Append param
Set param = cmd.CreateParameter("#Destination", adChar, adParamInput, 1, stDestination)
cmd.Parameters.Append param
rs.CursorType = adOpenStatic
rs.CursorLocation = adUseClient
rs.LockType = adLockOptimistic
'rs.Open cmd
Set rs = cmd.Execute
If rs!errstatusok = True Then
stMessage = "Operation appears to have been successful, check the DataSets Listing..." & Chr(13) & "Also, the Server returned the following information: ["
Else
stMessage = "Operation appears to have failed, check the DataSets Listing..." & Chr(13) & "Also, the Server returned the following information: ["
End If
For Each fld In rs.Fields
stMessage = stMessage & "| " & fld.Name & " / " & fld.Value & " |"
Next fld
stMessage = stMessage & "]"
MsgBox stMessage
This returns the folliwing:
Operation appears to have failed, check the DataSets Listing...
Also, the Server returned the following information: [| errStatusOK / False || countCurrent / 0 || countHistorical / 10 |]
Among the other parameter enumerations from which "adParamInput" is taken, another is "adParamOutput", which is to indicate an out parameter from a stored procedure, and "adParamInputOutput" for a parameter which goes "both directions," as it were. In your case, I believe "adParamOutput" would be appropriate. I hope this is what you're looking for.

How to create an ADODB Recordset From a Table Valued Function with Named Parameters

This works:
Dim rst As New ADODB.Recordset
rst.Open "SELECT * FROM dbo.ftblTest(1,2,3)", CP.Connection, adOpenKeyset, adLockReadOnly
But it would be nicer to do this:
rst.Open "SELECT * FROM dbo.ftblTest(#Param1=1,#Param2=2,#Param3=3)", CP.Connection, adOpenKeyset, adLockReadOnly
If I try the second method I get the error: "parameters were not supplied for the function ftblTest"
Is it possible to use named parameters with multi-statement table-valued functions?
Edit 1: Examples Added Using Command Object
First the SQL
create function ftblTest (#Input int)
RETURNS #Results TABLE (
OutputField int
)
AS
BEGIN
INSERT INTO #Results SELECT #Input
Return
End
Some Code (run from inside an Access 2003 ADP, with a connection to the correct SQL DB)
Public Sub test()
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
'method 1 works
rst.Open "SELECT * FROM dbo.ftblTest(2)", CurrentProject.Connection, adOpenKeyset, adLockReadOnly
Debug.Print rst.Fields(0)
rst.Close
With cmd
.ActiveConnection = CurrentProject.Connection
.CommandType = adCmdTable
'method 2 works
.CommandText = "dbo.ftblTest(3)"
Set rst = cmd.Execute
Debug.Print rst.Fields(0)
'method 3 fails
.CreateParameter "#Input", adInteger, adParamInput, , 4
.CommandText = "dbo.ftblTest(#Input)"
Set rst = cmd.Execute 'error here:-2147217900 Must declare the scalar variable "#Input".
Debug.Print rst.Fields(0)
End With
End Sub
How can I get the named parameters to work in method 3?
Edit 2: test code modified to use Parameters.Append
Public Sub test()
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
Dim p As New ADODB.Parameter
With cmd
.ActiveConnection = CurrentProject.Connection
.CommandType = adCmdTable
'Parameter Append method fails
p = .CreateParameter("#Input", adInteger, adParamInput, , 4)
Debug.Print p.Name, p.Type = adInteger, p.Direction = adParamInput, p.SIZE, p.Value 'note that name not set!
With p
.Name = "#Input"
.Type = adInteger
.Direction = adParamInput
.SIZE = 4 'this shouldn't be needed
.Value = 4
End With
Debug.Print p.Name, p.Type = adInteger, p.Direction = adParamInput, p.SIZE, p.Value 'properties now set
.Parameters.Append p
.CommandText = "dbo.ftblTest(#Input)"
Set rst = cmd.Execute 'error here:-2147217900 Must declare the scalar variable "#Input".
Debug.Print rst.Fields(0)
End With
End Sub
this still doesn't work.
Edit 3: I removed the # from create parameter
as suggested and tried the CommandText 3 ways and got 3 different errors:
.CommandText = "dbo.ftblTest"
error: Parameters were not supplied for the function 'dbo.ftblTest'.
.CommandText = "dbo.ftblTest()"
error: An insufficient number of arguments were supplied for the procedure or function dbo.ftblTest.
.CommandText = "dbo.ftblTest(Input)"
error: "Input" is not a recognized table hints option. If it is intended as a parameter to a table-valued function or to the CHANGETABLE function, ensure that your database compatibility mode is set to 90.
This should work:
Dim cmd As New ADODB.Command
With cmd
.ActiveConnection = CurrentProject.Connection
.CommandType = adCmdTable
'you need to add question a mark for each parameter
.CommandText = "dbo.ftblTest(?)"
'you can even add a order by expression like:
.CommandText = "dbo.ftblTest(?) ORDER BY ..."
.Parameters.Append .CreateParameter("#Input", adInteger, adParamInput, , 4)
Set rst = cmd.Execute
Debug.Print rst.Fields(0)
End With
Yes, you can use parameters with a table function.
rst.Open "SELECT * FROM dbo.ftblTest(#Param1,#Param2,#Param3)", CP.Connection, adOpenKeyset, adLockReadOnly
Before you open the database connection add parameters and set their values.
Don't use the # in the name of your parameter and don't list the parameter by name in the command text. I've always done this with a stored procedure, so I'm not sure exactly how the paranethesis are handle for the command text.
try:
.CreateParameter "Input", adInteger, adParamInput, , 4
And:
.CommandText = "dbo.ftblTest()"
Or:
.CommandText = "dbo.ftblTest"

Resources