Stored procedure, and using ADO to connect, i'm having problems with the quotes however..
x = "text'"
If instr(x,"'") then x=replace(x,"'","''")
'x = "text''" at this point
Set Rs = Server.Createobject("adodb.recordset")
Rs.Open "Select_SP #name='" & x & "'"
I thought i was doing this right.. But I guess not, because i'm getting this error:
Microsoft OLE DB Provider for SQL Server error '80040e14'
SELECT ID from Table where Name='text''
Shouldn't it be
Name = 'text'''
Why isn't SQL recognizing the double quotes using ADO?
The Select_SP Uses something like this:
SET #sql = 'SELECT ID from Table where Name='''+#name+''''
Exec(#sql)
Do I have this SP written correctly?
The short answer is, don't call procedures the way you're doing it. Use a Command instead. This is from memory, since I don't have a Windows system in front of me at the moment, but it should work:
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
Set Cmd.ActiveConnection = myConnectionVariableHere
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "Select_SP"
'Note: if the above two lines don't work, replace them with the following
'cmd.CommandType = adCmdText
'cmd.CommandText = "Select_CP #name=?"
cmd.Parameters.Append cmd.CreateParameter("name", adVarChar, adParamInput, len(x), x)
Rs.Open cmd
Now, all that said, I can't tell you why your procedure is giving that particular output since you're not showing us the code for it. But I'm fairly certain ADO isn't going to convert a pair of single quotes into a double quote - not sure why you'd expect it to.
Edit after seeing the OP's edit. Don't execute SQL that way unless you absolutely have to. You will only give yourself grief. I don't know what database you're using and that procedure syntax doesn't look familiar, but in Oracle you could write something like:
PROCEDURE sql_test(MyName IN VARCHAR2, MyCursor OUT SYS_REFCURSOR) IS
BEGIN
OPEN MyCursor FOR SELECT id FROM some_table WHERE name = MyName;
END;
Related
The weirdest thing. I have a simple procedure that I developed in Microsoft Access 2010 with a SQL Server 2012 backend. I am now trying to deploy this into production which is Access 2016 and a SQL Server 2014 backend.
I've compiled, compact and repaired in the new environment... but I can not get Access to execute this simple stored procedure. Even worse it still executes several other stored procedures fine... but a couple of them it times out and refuses to execute?
Here is my VBA and stored procedure:
Private Sub GenerateUnitKey(UnitColumns As String)
Dim Msg, Style, Title, Response As Variant
Dim lngProcessID As Long
Dim Conn As ADODB.Connection
Dim Cmd As ADODB.Command
Dim CurrentConnection As String
CurrentConnection = LinkMasterConnection()
Msg = "Are you sure you want to update the UnitKey with the selected columns?"
Style = vbYesNo + vbCritical + vbDefaultButton2
Title = "Save Campaign?"
Response = MsgBox(Msg, Style, Title)
If Response = vbYes Then
Call OpenSixHatLoader("Generating Unit Key Across Campaign Records", 1, "")
Set Conn = New ADODB.Connection
Conn.Open CurrentConnection
Set Cmd = New ADODB.Command
With Cmd
.ActiveConnection = CurrentConnection
.CommandText = "usp_GenerateUnitKey"
.CommandType = adCmdStoredProc
.CommandTimeout = 30
.Parameters.Append .CreateParameter("#UnitColumns", adVarChar, adParamInput, 4000, UnitColumns)
.Execute
End With
End If
End Sub
And stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[usp_GenerateUnitKey]
#UnitColumns AS VARCHAR(4000)
AS
SET NOCOUNT ON
DECLARE #SQL AS VARCHAR(MAX)
UPDATE tblStagingTable SET UnitKey =''
SET #SQL = 'UPDATE tblStagingTable SET UnitKey = ' + #UnitColumns + ' FROM tblStagingTable st'
EXEC(#SQL)
-- UPDATE Interests to match Staging Table
UPDATE tblInterests SET UnitKey = st.[UnitKey] FROM tblInterests i
INNER JOIN tblStagingTable st ON i.StagingTableID = st.StagingTableID
I am fairly confident there is nothing wrong with the code... as I said it worked fine in my development environment... even more I am manually able to execute the stored procedure within SQL Server. My SQL Server Native Client 11.0 connection works in executing other stored procedures... but for a couple of them it does not work. I am thinking I need to configure something within SQL Server itself or maybe within the Native Client 11.0 driver?
Unfortunately it gives no exception. I've set the CommandTimeout property to 0 and let it chug for a few hours hoping it would throw and exception to give me a clue but nothing... it just was frozen trying to execute. Any suggestions or ideas would be greatly appreciated because this one has me really stumped because it should be fine!
I would first launch SSMS, and from the SQL studio type in
Exec xxxxx ''
And ensure it runs (and use the SAME logon and connection to SSMS that you currently have for Access.
I would also consider creating a pass-though query, and saving that query in access. (set returns records = false if the sp does not return records). Then in code to run any proc, you can go:
With CurrentDb.QueryDefs("qryPass")
.SQL = "exec usp_GenerateUnitKey '" & UnitColumns & "'"
.Execute
End With
You note how simple the above code is - so if sp works from SSMS, then try the above code.
This was a difficult one that took me about 3 solid days of troubleshooting to get a solution to. Although I am not satisfied with the end solution as it should have just worked... but in the end my theory of the server being an Virtual Machine proved correct. When I deployed this exact same setup to Microsoft Access 2016 32 bit and SQL Server 2014 32 bit on a dedicated server it worked exactly as it was supposed to compared to the Azure VM and 1&1 Cloud Servers I had attempted to deploy to.
SQL Server integration with VM's is getting better from what all I have read, but apparently there is a ways to go. Maybe SQL Server needs to release a special VM version. Thank you to all those who took the time to look into this.
When I want to get the definition of a stored procedure (in SQL Server) I use SQL Server Management Studio.
I sometimes run the `sp_helptext' to output the definition of a stored procedure.
Link: https://msdn.microsoft.com/en-us/library/ms176112.aspx
In a nutshell, I'd like to have a simple html popup window that would output any stored procedure's definition to text.
The asp code below is making a successful connection to my Database, but I'm not getting any output.
<%
' .......
sql = "exec sp_helptext 'some_ProcName_Here'"
objRs.open sql, objConn
Text=objRs("Text")
response.write(Text)
%>
I also attempted creating a new Stored Procedure that takes 1 parameter, which would execute the sp_helptext.
<%
' .......
sql = "exec See_Proc_Definition #ProcName=some_ProcName_Here"
objRs.open sql, objConn
Text=objRs("Text")
response.write(Text)
%>
Neither of these display anything, but I don't get any returned errors neither.
Can anyone see what I'm doing wrong?
The problem is you are only displaying the first line of the sp_HelpText output. SQL Server returns the output as a single column recordset containing a column called [Text].
This means you need to iterate through the rows to display the rest of the output.
Using your first example;
<%
' .......
sql = "exec sp_helptext 'some_ProcName_Here'"
objRs.open sql, objConn
Do While Not objRs.EOF
Text=objRs("Text")
response.write(Text)
objRS.MoveNext
Loop
%>
This isn't ideal but will work, from experience (especially with more complex stored procedures) I find something like this is better in the long run;
Dim sql, cmd, rs, data
Set cmd = Server.CreateObject("ADODB.Command")
sql = "sp_HelpText"
With cmd
'Use your connection string instead of instantiating an ADODB.Connection object.
.ActiveConnection = conn_string
.CommandType = adCmdStoredProc
.CommandText = sql
.Parameters.Append(.CreateParameter("#objname", adVarWChar, adParamInput, 776))
.Parameters.Append(.CreateParameter("#columnname", adVarWChar, adParamInput, 128))
Set rs = .Execute(, Array("some_ProcName_Here"))
If Not rs.EOF Then data = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
Set cmd = Nothing
This method gives you a 2-Dimensional Array containing the row data in the data variable. You can then use standard Array techniques to manipulate the output.
Dim output, row, rows
If IsArray(data) Then
rows = UBound(data, 2)
For row = 0 To rows
output = output & "<br />" & data(0, row)
Next
Call Response.Write(output)
End If
Links
Using METADATA to Import DLL Constants - If your having trouble with the ADO constants (adCmdStoredProc etc.) this will fix it for you.
Background: Work on frontend Ms-Access 2010 and backend SQL server 2008 Managment Studio
For executing stored procedures I have been using a pretty lengthy process as seen here: in VBA
Set Conn = New ADODB.connection
Conn.ConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;....."
Conn.Open
Set cmd = New ADODB.Command
cmd.ActiveConnection = Conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "upGetTestIdForAnalyte"
cmd.Parameters.Append cmd.CreateParameter("#WOID", adVarChar, adParamInput, 60, MySampleName)
cmd.Parameters.Append cmd.CreateParameter("#Analyte", adVarChar, adParamInput, 60, MyAnalyte)
cmd.Parameters.Append cmd.CreateParameter("#SampleID", adVarChar, adParamInput, 60, MyConcentration
cmd.Execute
Conn.Close
Someone told me there was a better way to execute a stored procedure and the correct way would be something like this: in VBA
strsql = "Exec upGetTestIdForAnalyte(WOID, Analyte, SampleID)"
test = ExecuteNonQuery(strsql)
But I got a lot of errors for this process and I looked up ExecuteNonQuery and it said it was only for VB (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executenonquery.aspx). One of the advantages of this process would be its conciseness and the fact that it connects automatically to the current database. I would have to change the connection string in my current sp process because it is set to link to a test database not the actual one. Another advantage would be that it returns a value when executed. I would like my current process to do that because I want to somehow verify it ran and other stored procedures I need to make, need to return the number of records affected.
My questions are: Is the second method a legitimate process and is that the correct syntax? Also is there any difference in what each process accomplishes? Also is there a way for the first process to return a value when executed? Thank you for your time.
UPDATE: This is my stored procedure I'm currently working on. My sp sees if a testID exists or not, I will continue with the program after calling the sp if variable ThisTestId >0 else I will raise an error testid not found
CREATE PROCEDURE upGetTestIDForAnalyte #WOID nvarchar(60), #SampleID nvarchar(60),#Analyte nvarchar(60), #Test var(20) output
AS
SELECT TestID = t1.TestID
FROM tblWOSampleTest t1
JOIN tblTest t2
ON t1.TestID=t2.TestID;
WHERE #WOID = t1.WOID AND #SampleID = t1.SampleID AND #Analyte = t2.Analyte
GO
The examples posted here have way too much code.
The original question is the poster has seen some examples where only one or two lines of code is required.
In fact this code works and passes a parameter to a store procedure.
With CurrentDb.QueryDefs("MyPass")
.SQL = "exec MySproc" & ProducutID
.Execute
End If
The above is only two lines of code.
The advantages of this approach?
Note how we did not have to mess (or pass) with a connection string.
Note how we did not have to declare any connection object in code.
Note how we did not have to store or have the user name or password anywhere in the code.
Note how we don’t have to create a query def object in code either.
In fact the whole thing works without declaring ANY variables.
And the above could have been written on two lines of code, but I decided to post a massive 4 lines of code for increased readability.
The advantages of this setup are many, but the main reason is such an approach is MOST simple and easy to maintain.
The other posted solutions here serve only to force one to write many lines of code – this simply increases development costs for their employers.
I'll stay with first process and add an output parameter like this:
ccmd.parameters.Append ccmd.CreateParameter("OutParam", adInteger, adParamOuput, , NULL) ' output parameter
You need to add this parameter in stored procedure as well like this:
#OutParam int OUTPUT
EDIT Added OUT parameter, changed to integer in VBA code. See how ##ROWCOUNT work
CREATE PROCEDURE upGetTestIDForAnalyte #WOID nvarchar(60), #SampleID nvarchar(60),#Analyte nvarchar(60), #RecordsAfected int OUT
AS
SELECT TestID = t1.TestID
FROM tblWOSampleTest t1
JOIN tblTest t2
ON t1.TestID=t2.TestID;
WHERE #WOID = t1.WOID AND #SampleID = t1.SampleID AND #Analyte = t2.Analyte
set #recordsAfected = ##ROWCOUNT
GO
From Microsoft help site:
Function ExecuteSPT (sqltext As String, connectstring As String)
' Purpose: Run a temporary pass-through query.
' Accepts: sqltext: SQL string to run.
' connectstring: Connection string, which must be at least
' "ODBC;".
' Returns: nothing.
Dim mydb As Database, myq As QueryDef
Set mydb = DBEngine.Workspaces(0).Databases(0)
' Create a temporary QueryDef object that is not saved.
Set myq = mydb.CreateQueryDef("")
' Set the ReturnsRecords property to False in order to use the
' Execute method.
myq.returnsrecords = False
myq.connect = connectstring
myq.sql = sqltext
myq.Execute
myq.Close
End Function
It can be easily altered to return as DAO.Recordset. DAO is still the "native" data access in MS Access.
I have the following UDF in excel which uses ADO to connect to my MSSQL server. There it should execute the scalar udf "D100601RVDATABearingAllow".
For some reason the parameters that I try to append are not send to the sql server. At the server only:
SELECT dbo.D100601RVDATABearingAllow
arrives.
MY EXCEL UDF:
Function RVDATA(Fastener) As Long
Dim cnt As ADODB.Connection
Dim rst As ADODB.Recordset
Dim Cmd1 As ADODB.Command
Dim stSQL As String
Const stADO As String = "Provider=SQLOLEDB.1;Data ................"
'----------------------------------------------------------
Set cnt = New ADODB.Connection
With cnt
.ConnectionTimeout = 3
.CursorLocation = adUseClient
.Open stADO
.CommandTimeout = 3
End With
'----------------------------------------------------------
Set Cmd1 = New ADODB.Command
Cmd1.ActiveConnection = cnt
Cmd1.CommandText = "dbo.D100601RVDATABearingAllow"
Cmd1.CommandType = adCmdStoredProc
'----------------------------------------------------------
Set Param1 = Cmd1.CreateParameter("Fastener", adInteger, adParamInput, 5)
Param1.Value = Fastener
Cmd1.Parameters.Append Param1
Set Param1 = Nothing
'----------------------------------------------------------
Set rst = Cmd1.Execute()
RVDATA = rst.Fields(0).Value
'----------------------------------------------------------
rst.Close
cnt.Close
Set rst = Nothing
Set cnt = Nothing
'----------------------------------------------------------
End Function
When I use adCmdStoredProc the whole thing fails and in the vba debugger the properties of the recordset has a lot of "Operation is not allowed when object is closed" (may sound a bit different, the message is translated)
When I don't use adCmdStoredProc I get the message that the variable Fastener was not provided.
I think that maybe something is wrong in the way I open the recordset.
In other treads I read about using the "SET NOCOUNT ON" option, but that did not work either.
Does anyone have a idea?
Regards Lumpi
Ran into this error as well (in my case I am using a Stored Procedure to retrieve some information). I had made some changes which caused the execution to malfunction.
The error disappeared when I put SET NOCOUNT ON as the first statement of the Stored Procedure.
You do not need to SELECT the server side function, just provide its name ("[tra-CAE400-1].dbo.D100601RVDATABearingAllow") in the .CommandText property.
Also you should set the .CommandType property to "stored-procedure" (property reference on w3schools.com).
Then adodb will know that you are talking about calling a function, and not trying to send a plain sql-command.
Chances are that it will then allow you to define the parameters on the command object.
But the parameters you define on the command object should correspond exactly (in name and type) to the ones that are defined as the arguments of the function in the sql server.
An example from microsoft.com on using the command-object with a stored procedure
ADO Reference on microsoft.com
Another possible cause of this is debug statements. I just spent far too long trying to work out why this wouldn't work for me, the Proc on the database worked fine, the data it was supposed to insert was inserted, the VBA code worked fine, but there was nothing in the recordset.
Final solution was to go through the procs that had been built and remove the PRINT statements.
To test if this is the problem, run your proc on SQL Server manually, then look at the messages tab of the results, if there's anything there other than "Command(s) completed successfully." you need to eliminate those messages. "SET NOCOUNT ON" will get rid of the row count messages, but there may be others.
I'm assuming that after 5 years the OP has solved this particular problem, so this is just for anyone like me that finds this while searching for the same problem.
I also ran into this with a stored procedure. Did you SET NOCOUNT = OFF; at the bottom of your code? That is what worked for me after lots of googling. Also, if you have any other code that runs, you have to wrap it in Nocount = on/off, INCLUDING insert and update statements. You would think that an insert statement wouldn't matter but wrapping the code that way is what kept me from committing suicide today.
In our shop we often use lines like this in our stored procedures to assist with debugging:
RAISERROR('Debug message here',0,1) WITH NOWAIT;
This also breaks opening a recordset in Excel vba. I believe the complete answer for this question is, in the stored procedure:
use SET ROWCOUNT OFF
remove all PRINT statements
remove all RAISEERROR statements used for debugging (ie severity of 0)
I have a script that runs a stored procedure in my SQL server database, the problem is the stored procedure takes a uniqueidentifier parameter. I have a function that grabs a session id from the database (which is an nvarchar), so VBScript makes it a string and I need to convert it to pass it to the stored procedure.
Function GetOpenSession
Set conn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
conn.Open "Provider=SQLOLEDB.1;Integrated Security=SSPI;Data Source=" & Source
rs.CursorLocation = 3
rs.Open "SELECT top 1 OpenSession FROM OpenSessions with (nolock)" , conn, 3, 3
If rs.RecordCount = 0 Then
MsgBox "No Connection"
Else
GetOpenSession = rs.Fields(0).Value
End If
End Function
I get "Invalid character value for cast specification" when I try to execute the stored procedure.
set cnParam = cmd.CreateParameter("#ActiveSession",72,1,,GetOpenSession)
cmd.Parameters.Append cnParam
I can't change anything in the database, so I need a way to overcome this in my script.
I believe VBScript expects GUIDs to be brace terminated.
Is your Session id of the same format as the following {D6CA6263-E8E1-41C1-AEA6-040EA89BF030}
Depending on the data type of the SELECT OpenSession, you may be able to cast/convert it in the query and VBScript may possibly keep the data type as a GUID:
SELECT top 1 CONVERT(uniqueidentifier, OpenSession)
FROM OpenSessions with (nolock)
When you use GetOpenSession or rs.Fields(0).Value, hopefully VBScript will keep it as a GUID.
The other possibility seems to be a Win32 API using CoCreateGuid and StringFromGUID2. An example is found here, but it requires external Win32 functions and a Type for GUID.
I usually change the parameter type of the stored procedure to varchar(38).
SQL Server makes a better job of coercing the string to a GUID when needed.
What is the value of GetOpenSession after you have assigned it? Which datatype? It sounds like it is not compatible with type 72 (GUID), which you are stating in the CreateParameter call.
You could forget about using ADO Commands altogether and just execute the stored procedure using plain SQL.
Set rs = CreateObject("ADODB.Recordset")
rs.Open "EXEC usp_MySP '" & GetOpenSession & "'", cnn
Obviously it's terrible to build SQL commands like this, but it's just for a test, after all...