How do I use ExecuteScalar with a stored Procedure? - c#

I'm trying to get a count of column records in a Sql database and show the result in a MessageBox.
This is my code:
public DataTable CheckIfNameExist(string name)
{
con = Connect();
cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "spCheckIfNameExist";
cmd.Parameters.AddWithValue("#Name", SqlDbType.NVarChar).Value = name;
MessageBox.Show(name);
Int32 totalNames = (Int32) cmd.ExecuteScalar();
string tNames = totalNames.ToString();
MessageBox.Show(tNames);
}
And this is my sp:
#Name nvarchar(50) = null
As
Begin
SELECT COUNT(*) from OrdersSent where CustomerName LIKE #Name + '%'
End
Problem:
It always returns 0.

There are a couple of errors in your code:
You should write it as:
cmd.CommandText = "spCheckIfNameExist";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
First you need to tell the ADO engine that you are calling a stored procedure and not a simple command text, but you also need to use Add instead of AddWithValue to be precise on the type of the parameter passed to the SP. Your code creates a parameter int becase the second parameter of the AddWithValue is the Value of the parameter not the type.

You have a few problems in the c# code - the most important is probably this:
cmd.Parameters.AddWithValue("#Name", SqlDbType.NVarChar).Value = name;
Don't use AddWithValue. Use Add.
Also, you didn't specify the command type - the default is Text.
And you are using fields for SqlConnection and SqlCommand - which is also the wrong thing to do. You should create and dispose both of them inside each method you are using them.
A better version of your code would be this:
using(var con = new SqlConnection(ConnectionString))
{
using(var cmd = new SqlCommand("spCheckIfNameExist", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
con.Open();
var tNames = cmd.ExecuteScalar().ToString();
}
}
Another thing that puzzles me is why a method called CheckIfNameExist returns a DataTable. I would expect it to simply return a bool.
If you really only want to check if the name exists, you can do this better on both the SQL level and the c# level.
A better SQL would be something like this:
SELECT CAST(CASE WHEN EXISTS(
SELECT 1
FROM OrdersSent
WHERE CustomerName LIKE #Name + '%'
) THEN 1 ELSE 0 END AS bit)
And on the c# level, bit translates directly to bool, so the code can simple be this:
public bool CheckIfNameExist(string name)
{
using(var con = new SqlConnection(ConnectionString))
{
using(var cmd = new SqlCommand("spCheckIfNameExist", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
con.Open();
return (bool)cmd.ExecuteScalar();
}
}
}
And another note - you should avoid using the sp prefix for stored procedures.
Microsoft have reserved this prefix for built in system procedures.
For more information, read Aaron Bertrand's Is the sp_ prefix still a no-no?, where you'll see that the short answer to this question is "Yes".
The sp_ prefix does not mean what you think it does: most people think sp stands for "stored procedure" when in fact it means "special." Stored procedures (as well as tables and views) stored in master with an sp_ prefix are accessible from any database without a proper reference (assuming a local version does not exist). If the procedure is marked as a system object (using sp_MS_marksystemobject (an undocumented and unsupported system procedure that sets is_ms_shipped to 1), then the procedure in master will execute in the context of the calling database.

You need to specify the type of your command like this:
cmd.CommandText = "spCheckIfNameExist";
cmd.CommandType = CommandType.StoredProcedure;
See also:
What is the benefit of using CommandType.StoredProcedure versus using CommandType.Text?
Although specify the type directly and use the Value property is more better than AddWithValue:
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
The following article could be also interesting:
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/

Related

Call DB2 stored procedure from C#

After reading an interesting article online : Calling DB2 stored procedures from .NET applications
I'd like to share an issue recently encountered with a derived code :
DateTime transa_date = DateTime.ParseExact(trandate, "yyyy-MM-dd",
CultureInfo.InvariantCulture);
DB2Connection conn = new DB2Connection(MyDb2ConnectionString);
conn.Open();
try
{
// MyDb2Connection.Open();
// conn.Open();
// assume a DB2Connection conn
DB2Transaction trans = conn.BeginTransaction();
cmd = conn.CreateCommand();
procName = "MYTBLSCHEMA.TEST";
procCall = "CALL MYTBLSCHEMA.TEST(#NAME, #ADDRESS_LINE, #REGNUM, #TRANSA)";
cmd.Transaction = trans;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = procCall;
// Register input-output and output parameters for the DB2Command
cmd.Parameters.Add( new DB2Parameter("#NAME", name)); #of string type
cmd.Parameters.Add( new DB2Parameter("#ADDRESS_LINE", adr)); #of string type
cmd.Parameters.Add( new DB2Parameter("#REGNUM", reg)); #of string type
cmd.Parameters.Add( new DB2Parameter("#TRANSA", transa_date)); #of date type (in DB2 table)
// Call the stored procedure
Console.WriteLine(" Call stored procedure named " + procName);
cmd.ExecuteNonQuery();
}
The above code neither generates an exception at cmd.ExecuteNonQuery() nor inserts the (expected) row into the table.
Hence, a Hope to understand through this post the rationale underlying such phenomenon.
Thanks.
N.B: Executing (manually)
CALL MYTBLSCHEMA.TEST('test', 'test_address_', 'test_num', 2021-01-01)
from the IDE does work (e.g. insert the row into the table).
DB2 version: 11.5.6.0.00000.008
I'd either remove this line:
DB2Transaction trans = conn.BeginTransaction();
Or I'd add this line at the end of the try:
trans.Commit();
As to which you'd choose; as it's a single stored procedure, unless there's some internal overriding concern within the sproc that makes sense to have a transaction to be started outside it cover it, I'd remove it. If you have, or plan to have multiple operations that must either all-succeed or all-fail, then I'd keep it/commit it..

SqlDateTime overflow then Sql column type is ... datetime2(7) [duplicate]

I would like to know the difference between these 2 notations.
First of all I have a stored procedure
CREATE PROCEDURE AddSomething( #zonename varchar(50), #desc varchar(255), #TheNewId int OUTPUT ) AS
BEGIN
INSERT INTO a_zone(zonename, descr) VALUES(#zonename, #desc)
SELECT #TheNewId = SCOPE_IDENTITY()
END
What is the difference if I add parameters in this manner
SqlCommand Cmd = new SqlCommand("AddSomething", oConn);
Cmd.CommandType = CommandType.StoredProcedure;
SqlParameter oParam1 = Cmd.Parameters.AddWithValue("#zonename", sName);
SqlParameter oParam2 = Cmd.Parameters.AddWithValue("#desc", description);
and
SqlCommand Cmd2 = new SqlCommand("AddSomething", oConn);
Cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Parameters.Add("#zonename", SqlDbType.VarChar).Value = zonename.Text.Trim();
cmd2.Parameters.Add("#desc", SqlDbType.VarChar).Value = desc.Text.Trim();
Here are some explanations:
difference between command Add and AddWithValue
Dim cmd as new SqlCommand("SELECT * FROM MyTable WHERE MyDate>#TheDate",conn)
cmd.Parameters.Add("#TheDate",SqlDbType.DateTime).Value="2/1/2007"
vs
cmd.Parameters.AddWithValue("#TheDate","2/1/2007")
"Add forces the conversion from string to date as it goes into the parameter. AddWithValue would have simply passed the string on to the SQL Server.
When using Parameters.Add - the SqlDbType is known at compile time
When using Parameters.AddWithValue the method has to box and unbox the value to find out its type.
Additional benefits of the former is that Add is a bit more code safe
and will assist against SQL injection attacks , code safe in terms
that if you try to pass a value that doesn't match the SqlDb type
defined - the error will be caught in .Net code and you will not have
to wait for the round trip back.
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters.aspx
http://msdn.microsoft.com/en-us/library/yy6y35y8.aspx
Edit:
example to get an Output-Parameter:
C#
cmd.Parameters.Add(new SqlParameter("#TheNewId", SqlDbType.Int, int.MaxValue));
cmd.Parameters("#TheNewId").Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
int theNewID = (int)cmd.Parameters("#TheNewId").Value;
VB.Net
cmd.Parameters.Add(New SqlParameter("#TheNewId", SqlDbType.Int, Int32.MaxValue))
cmd.Parameters("#TheNewId").Direction = ParameterDirection.Output
cmd.ExecuteNonQuery()
Dim theNewID As Int32 = DirectCast(cmd.Parameters("#TheNewId").Value, Int32)
When you use AddWithValue, the datatype will be worked out (as best possible) based on the types of the variables passed to the method - assuming sName and description are string variables, the params will be passed in as NVARCHAR.
I personally prefer the 2nd approach, being explicit with the data types (plus I actually specify the sizes too) so that they are guaranteed to match the sproc definition and avoid any unexpected behaviour.

Call SQL Server stored procedure with parameters using C#

I am trying to call a very simple SQL Server stored procedure using C# code. I have a class which has authenticate method. I am passing text box values (userID, password) to this method and it keeps on throwing me error about required parameter not being passed. I am basically a Business Intelligence professional working on C# project. Help will be appreciated.
Here is the code I am executing:
sqcon.Open();
SqlCommand cmd = new SqlCommand("Users.PR_Authenticate_WebUsers",sqcon);
cmd.Parameters.Add("#In_UserID", SqlDbType.VarChar).Value = "f";
cmd.Parameters.Add("#In_PassWord", SqlDbType.NVarChar).Value = "f";
cmd.Parameters.Add("#Out_IsAuthenticatedUser", SqlDbType.Bit);
cmd.Parameters["#Out_IsAuthenticatedUser"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
sqcon.Close();
I don't understand when I am passing parameter values explicitly why it complains about value not being passed? Am I missing something?
Hmmm looks like you are not telling the command object that it is a stored procedure not a regular query try this one
sqcon.Open();
SqlCommand cmd = new SqlCommand("Users.PR_Authenticate_WebUsers",sqcon);
cmd.CommandType = CommandType.StoredProcedure;
//Add parameters like this
cmd.Parameters.Add(new SqlParameter("#In_UserID", "f"));
sqcon.Close()

C# Stored procedure or function expects parameter which is not supplied

I am fairly new to C# and I'm trying to set up call to a stored procedure in my database which takes one parameter.
I get the error "Procedure or function 'SP_getName' expects parameter '#username', which was not supplied. "
My Stored procedure works ok when I supply it with the parameter and I run it via SQL management studio.
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[SP_getName]
#username = 'bob101'
SELECT 'Return Value' = #return_value
GO
However when I try and call it the error is with how I'm passing the parameter in, but I can't spot what the issue is.
//create a sql command object to hold the results of the query
SqlCommand cmd = new SqlCommand();
//and a reader to process the results
SqlDataReader reader;
//Instantiate return string
string returnValue = null;
//execute the stored procedure to return the results
cmd.CommandText = "SP_getName";
//set up the parameters for the stored procedure
cmd.Parameters.Add("#username", SqlDbType.NVarChar).Value = "bob101";
cmd.CommandType = CommandType.Text;
cmd.Connection = this.Connection;
// then call the reader to process the results
reader = cmd.ExecuteReader();
Any help in spotting my error would be greatly appreciated!
I've also tried looking at these two posts, but I haven't had any luck:
Stored procedure or function expects parameter which is not supplied
Procedure or function expects parameter, which was not supplied
Thanks!
You have stated:
cmd.CommandType = CommandType.Text;
Therefore you are simply executing:
SP_getName
Which works because it is the first statement in the batch, so you can call the procedure without EXECUTE, but you aren't actually including the parameter. Change it to
cmd.CommandType = CommandType.StoredProcedure;
Or you can change your CommandText to:
EXECUTE SP_getName #username;
As a side note you should Avoid using the prefix 'sp_' for your stored procedures
And a further side note would be to use using with IDisposable objects to ensure they are disposed of correctly:
using (var connection = new SqlConnection("ConnectionString"))
using (var cmd = new new SqlCommand("SP_getName", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#username", SqlDbType.NVarChar).Value = "bob101";
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// Do something
}
}
}
I had this problem, but it wasn't about parameter name of Command Type.
My problem was that when C# calls SP, for each parameter that has no value passes 'default' keyword (i found it in SQL Profiler):
... #IsStop=0,#StopEndDate=default,#Satellite=0, ...
in my case my parameter Type was DateTime :
#StopEndDate datetime
. I Solved my problem by seting default value to this parameter in Stored Procedure :
#StopEndDate datetime=null
Try remove #:
cmd.Parameters.Add("username", SqlDbType.NVarChar).Value = "bob101";

Procedure or Function Expects Parameter Which Was Not Supplied #2

I am currently trying to complete a transaction for a web based app, however;
Procedure or function 'completeTransaction' expects parameter '#dateTime', which was not supplied.
Here is copy of the function.
public static void completeTransaction(string storeCode, string employeeId, DateTime Date, string itemListNoId)
{
using (SqlConnection conn = new SqlConnection("Data Source = ; Initial Catalog =Business ; Integrated Security = true;"))
{
using (SqlCommand command = new SqlCommand("dbo.completeTransaction", conn))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#storeCode", SqlDbType.Int).Value = storeCode;
command.Parameters.Add("#employeeId", SqlDbType.Int).Value = employeeId;
**command.Parameters.Add("#Date", SqlDbType.DateTime).Value = Date;**
command.Parameters.Add("#itemListNoId", SqlDbType.Int).Value = itemListNoId;
conn.Open();
command.ExecuteNonQuery();
conn.Close();
}
}
}
My sql table contains the following tables and types (storeCode, INT, employee, INT, Date, DATETIME, itemListNoId, INT)
You do not pass a parameter called #dateTime. It seems like this line
command.Parameters.Add("#Date", SqlDbType.DateTime).Value = Date;
Should be
command.Parameters.Add("#dateTime", SqlDbType.DateTime).Value = Date;
But without the SP source code it is hard to be sure. Keep in mind that SQL Server is complaining about the NAME of the parameter not about its type.
expects parameter '#dateTime'
You passed a parameter named #Date.
the name of the parameter is wrong:
command.Parameters.Add("#dateTime", SqlDbType.DateTime).Value = Date;
If you are getting this and you have passed in the correctly named parameter, check that the CommandType is set to Stored procedure
cmd.CommandType = CommandType.StoredProcedure;
I was seeing these same symptoms spent an embarrassingly long time tracking down how each parameter was getting to the stored proc.
As previous answers have correctly mentioned, most probable reasons for this error are either forgetting to add parameter(s) to the SqlCommand or forgetting to set command's type to CommandType.StoredProcedure
In case you have already set above correctly and still pulling your hair, then this might be the reason.
If you set parameters value to null (e.g. mySQLParam1.Value = valuePassedToMe and if valuePassedToMe is null) then you will get the same error (i.e. Procedure or function '...' expects parameter '...', which was not supplied).
This can be solved by assigning DBNull.Value when the value needs to be null
i.e.
mySQLParam1.Value = valuePassedToMe ?? (object)DBNull.Value;
When you assign null to a parameter ADO.Net converts it to default. Below is an example from SQL Server Profiler.
exec dbo.MyStoredProcedure #mySQLParam1=default,#mySQLParam2=default,#mySQLParam3=default,...
When you assign DBNull.Value the generated SQL becomes:
exec dbo.MyStoredProcedure #mySQLParam1=NULL,#mySQLParam2=NULL,#mySQLParam3=NULL,...

Categories