Calling an SP using ExecuteNonQuery - sql-server

I have some general purpose code in my app for calling non-query commands like inserts:
DBComm.CommandText = SQL
DBComm.Connection = Cnn
Ans = DBComm.ExecuteNonQuery
I'm using this to call an SP that takes two strings and returns an int:
Dim SQL As String = "EXEC Import_Validation " & Code & "," & User
Return DbS.Execute(SQL)
This works fine, with the exception that the return value is not the value of the SP (is it a job id of some sort?). So I modified it slightly:
Param = New SqlParameter("#RETURN_VALUE", SqlDbType.Int)
Param.Direction = ParameterDirection.ReturnValue
DBComm.Parameters.Add(Param)
DBComm.CommandText = SQL
DBComm.Connection = Cnn
DBComm.ExecuteNonQuery
This runs, but always returns 0 for RETURN_VALUE. I suspect this is because I do not have the following line:
DBComm.CommandType = CommandType.StoredProcedure
Is that suspicion correct?
However, if I add this line, the SQL no longer works, complaining Could not find stored procedure "Import_Validation '1234', 'maury'. I assume that is because it thinks the string I passed in is just the name, and is being confused by the parameters. I could add the parameters as input parameters on DBComm, but then the method would be specific to a particular SP.
So is there a way I can call an SP using SQL I construct and still get a parameter back out?

If you are just returning an integer, I've used this:
Param.value=cmd.ExecuteScalar()

I Cannot guess nor explain why you had trouble executing the store procedure, since you didn't share the full code (full part of the code that have issue). However, generally speaking, when you use ExecuteNonQuery() you're supposed to use a valid T-SQL. By default, the commandType is Text. So, if you need to execute a store procedure, you'll need to change the command type to StoredProcedure before executing the query. So, I would say your guess is correct in this line :
DBComm.CommandType = CommandType.StoredProcedure
Also, in your code, you declared a #RETURN_VALUE parameter, but I couldn't see anything calling its value !? So, maybe this is the issue ?
anyhow, check this :
Using connection As New SqlConnection(ConnectionString)
command As New SqlCommand("dbo.Import_Validation", connection)
command.CommandType = CommandType.StoredProcedure
command.Parameters.Add("#Code", SqlDbType.VarChar, 250)
command.Parameters.Add("#User", SqlDbType.VarChar, 250)
command.Parameters.Add("#RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue
command.Parameters("#Code").Value = Code
command.Parameters("#User").Value = User
connection.Open()
command.ExecuteNonQuery()
'IF returned value is more than one row, then use reader instead
Dim return_value As Integer = Convert.ToInt32(command.Parameters("#RETURN_VALUE").Value)
connection.Close()
End Using

Related

Storing query count in a vb variable

I've been experimenting with what I can do with a database, but I'm unfamiliar with aspects like storing a query result in a variable. I've used this snippet to query my database with more than one record, but the result I keep getting is zero. Can someone explain how this works? Here's my snippet...
str = "SELECT COUNT(Nickname) FROM Backup"
cmd.CommandText = str
cmd.Connection = myConn
myConn.Open()
cntPlns = cmd.ExecuteNonQuery()
MessageBox.Show(cntPlns.ToString)
The connection is there, but my result always comes out zero...thanks for any suggestions.
See ExecuteNonQuery doesn't return results for ...nonquery is the wrong cmd.
Try this>>
str = "SELECT COUNT(Nickname) as myCount FROM Backup"
cmd.CommandText = str
cmd.Connection = myConn
myConn.Open()
Using cntPlns As SqlDataReader = command.ExecuteReader
If cntPlns.Read Then
MessageBox.Show(cntPlns.GetInt32(0).ToString) ' the first column
End If
End Using
You should be calling ExecuteScalar, not ExecuteNonQuery. ExecuteNonQuery is for executing a non-query, i.e. a SQL statement that does not produce a result set. ExecuteScalar is for executing a query and retrieving a scalar, i.e. a single value, which comes from the first column of the first row of the result set, whether or not that result set contains more data.
For the record, you get zero every time because ExecuteNonQuery returns the number of rows affected by the SQL statement, where affected means changed. A SELECT statement affects no rows so zero is the correct result.
It might serve you well to check out my ADO.NET examples to see what objects and members to use where and when.

Replace all instances of a variable referenced in VB code based on condition

so recently with help I got to the point of using the output parameter of a sql stored procedure in a vb code,this is a follow up question on how to reference and replace a output parameter based on a condition, now the issue is I am trying to replace all instances of that variable in the code based on a IF condition.
The code I am using below generates the value I want to append based on the condition:
Dim DocName As String
DocName = drDocDetailData("DocName").ToString
Using DocDetail As New SqlCommand
With DocDetail
.Connection = con
.CommandType = CommandType.StoredProcedure
.CommandText = ("up_AddDocumentSuffix")
.Parameters.AddWithValue("#DocName", con)
.Parameters.Add("#DocSuffix", SqlDbType.VarChar, 50).Direction = ParameterDirection.Output
.ExecuteNonQuery()
suffix = DocDetail.Parameters("#DocSuffix").Value
Docname = sb.Append(DocName).Append(suffix).ToString()
End With
End Using
Now I have this docname parameter referenced throughout the VB code in different sections:
.Parameters.AddWithValue("#DocName", Trim(drDocDetailData("DocName").ToString))
I want to replace it with the DocName appended value in the first code only if the client is this specific client (client name = "company1"), is there any way to replace a certain parameter in the entire code based on a condition?

ADODB open recordset fails / "Operation is not allowed when object is closed"

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)

Returning a boolean from a T-SQL Stored Procedure

What's the most efficient way to return a boolean (true/false) out of a T-SQL Stored Procedure? I want it to do a query and return whether it succeeded or not. I'm calling via ASP.
Let me be a little more specific about what I'm doing.
If a record exists in a table (indicating a document is already reserved and can't be checked out), I want to notify the user on the front end. I'll determine that by checking Exists... in T-SQL and then somehow pushing that back to Classic ASP (return value, parameter, recordset field).
Does that make any answer more reasonable?
I have this function in ASP that assume that the SP takes the last parameter as an integer output value.
Returning and integer is better, cause you can return several states, and not only true/false.
Function RunSPReturnInteger(strSP , params())
On Error resume next
''// Create the ADO objects
Dim cmd
Set cmd = server.createobject("ADODB.Command")
''// Init the ADO objects & the stored proc parameters
cmd.ActiveConnection = GetConnectionString()
cmd.CommandText = strSP
cmd.CommandType = adCmdStoredProc
''// propietary function that put the params in the cmd
collectParams cmd, params
''// Assume the last parameter is outgoing
cmd.Parameters.Append cmd.CreateParameter("#retval", adInteger, adParamOutput, 4)
''// Execute without a resulting recordset and pull out the "return value" parameter
cmd.Execute , , adExecuteNoRecords
If err.number > 0 then
BuildErrorMessage()
exit function
end if
RunSPReturnInteger = cmd.Parameters("#retval").Value
''// Disconnect the recordset, and clean up
Set cmd.ActiveConnection = Nothing
Set cmd = Nothing
Exit Function
End Function
Return a bit: "an integer data type that can take a value of 1, 0, or NULL."
Not a good idea.
A return value, output parameter or a recordset will be undefined or not set or partial if you have an error. For example, a CAST error will abort the code (without TRY/CATCH).
A far better method will rely on Exception handling, like this:
BEGIN TRY
...
--assume worked
END TRY
BEGIN CATCH
DECLARE #foo varchar(2000)
SET #foo = ERROR_MESSAGE()
RAISERROR (#foo, 16,1)
END CATCH
However, I suspect I could be answering your later question about "why didn't SQL Server do ...?"...

T-SQL stored procedure returns null in code, but works in console

I have a stored procedure
CREATE procedure [dbo].[get_unique_identifier]
AS
DECLARE #ret_val INT
UPDATE seq SET #ret_val = id = id + 1
RETURN #ret_val
that queries a table (seq) that has a single int column and single row, increments the value and then then returns it. Don't ask why I'm doing this, but in short, the idea is to simulate a PostgreSQL sequence and no, an identity column would not do the job. Anyway, this works fine in SQL Management Studio, where sequential executions of
DECLARE #returned INT
EXEC #returned = get_unique_identifier
SELECT #returned
produce the expected output. Unfortunately, I can't seem to get the returned value in the application I'm working on
OdbcCommand command = new OdbcCommand("get_unique_identifier");
command.CommandType = CommandType.StoredProcedure;
OdbcParameter return_param = new OdbcParameter("#RETURN_VALUE", OdbcType.BigInt);
return_param.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(return_param);
Util.SQLExecuteParameterizedNonQuery(command);
Console.WriteLine(command.Parameters["#RETURN_VALUE"].Value.ToString());
The output is an empty string, but the value itself is DBNull.Value. The OdbcType.BigInt is left over from some testing I was doing. It was initially Int.
Edit: This is clearly a bug with ODBC. A workaround is posted below. Don't use ODBC if you don't have do.
I am sorry to have to say, but this might be due to using the Odbc
I tried this using out SqlClient database object and it returned the values as expected.
SqlCommand command = new SqlCommand("ZZZ_get_unique_identifier");
command.CommandType = CommandType.StoredProcedure;
SqlParameter return_param = new SqlParameter("#RETURN_VALUE",SqlDbType.BigInt);
return_param.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(return_param);
SqlConnection con = new SqlConnection(dbM.DefaultConnectionString);
con.Open();
command.Connection = con;
command.ExecuteNonQuery();
int i = Convert.ToInt32(command.Parameters["#RETURN_VALUE"].Value.ToString());
con.Close();
The return value of stored procedures is Int (32-bit), not BigInt (64-bit), but I'm not sure that this would be the problem with your code.
Have you not tried using an output variable instead...I am jogging my memory and think that the line command.Parameters["#RETURN_VALUE"].Value.ToString() could be this...The reason it worked in SQL Management Studio because you declared a variable and used it in an TSQL EXEC statement. I hope this answer somehow gives you a hint..
Hope this helps,
Best regards,
Tom.

Resources