I have this SqlCommand, but i dont know, how i give the return value?
string param = Request.QueryString["id"];
System.Data.SqlClient.SqlConnection se = new System.Data.SqlClient.SqlConnection(GetConnectionString());
{
System.Data.SqlClient.SqlCommand cme;
se.Open();
cme = new System.Data.SqlClient.SqlCommand("select Sum(case when (Domaci_tym = 'Tupesy') then Domaci_branky else Hoste_branky end) from Zapas AS branky where (ID_zapas=#ID_zapas)", se);
cme.Parameters.AddWithValue("#ID_zapas", param);
cme.ExecuteNonQuery();
se.Close();
Change this line cme.ExecuteNonQuery(); to:
double sum = 0d;
var result = cme.ExecuteScalar(); //returns object that needs casting to get proper value
if (result != null && double.TryParse(result.ToString(), out sum))
{
//query returned valid sum
}
More info about that method here
Related
I'm trying to write a method that returns me the sum of a column from entries between two dates. However it keeps returning a DBnull no matter what. I have other similar methods that work when the queries are simpler (no SUM, simple select * where statement). performQuery() is just helper method that returns a filled datatable with the query results.
public static int getBookedQuantity(int shopID, int bikeID, DateTime datetime)
{
string query = "SELECT sum(quantity) as \"quantity\" FROM booking WHERE bikeID=#bikeID AND shopID = #shopID AND starttime >= #Datetime AND endtime < #Datetime";
SqlParameter param1 = new SqlParameter("#bikeID", bikeID);
SqlParameter param2 = new SqlParameter("#shopID", shopID);
SqlParameter param3 = new SqlParameter("#Datetime", SqlDbType.DateTime);
param3.Value = datetime;
DataTable bookingData = performQuery(query, param1, param2, param3);
DataRow[] row = bookingData.Select();
int totalBooked = 0;
if ((row.Count()) > 0 && (bookingData != null)) // if there are rows returned
totalBooked = Convert.ToInt32(row[0]["quantity"]);
return totalBooked;
}
Thank you in advance!
Try modifying query to
string query = "SELECT sum(quantity) as 'quantity' FROM booking WHERE bikeID=#bikeID AND shopID = #shopID AND starttime >= #Datetime AND endtime < #Datetime";
DataTable is not a correct way to get the sum. To fix your problem you have to do this:
var sum = Convert.ToInt32(bookingData.Rows[0]["quantity"]);
return sum;
But, the correct way to execute this command, is this:
var statement = "SELECT COUNT(*) ...";
var command = new SqlCommand(statement, connection);
command.AddParam(param1);
command.AddParam(param2);
command.AddParam(param3);
var sum = Convert.ToInt32(command.ExecuteScalar());
return sum;
Please, refer to MSDN doc about scalar: https://msdn.microsoft.com/it-it/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx
Hope this can help.
If the query returns null the goal is to get it to return 0, else return the number. The SUM statement returns the sum of the column values in column ConcurrentUsers.
The code below returns a casting error:
Specified cast is not valid.
It could be because the query is returning a null and is having trouble converting it to int.
Below is the attempt.
Please edit question if anything should be clarified.
SQL query:
string query = #"SELECT SUM(CAST(ConcurrentUsers AS INT))
FROM [website].[db]
WHERE(ConcurrencyLicensing NOT LIKE 0)";
Return value:
SqlConnection conn = new SqlConnection(entityBuilder.ProviderConnectionString);
SqlCommand cmd = new SqlCommand(query, conn);
try
{
conn.Open();
object userNameObj = cmd.ExecuteScalar();
if(userNameObj != null)
{
int getUserName = (int)userNameObj;
return getUserName;
}
else
{
return 0;
}
}
finally
{
conn.Close();
}
Did you try COALESCE ?
string query = #"SELECT COALESCE(SUM(CAST(ConcurrentUsers AS INT)), 0) FROM [website].[db]
WHERE(ConcurrencyLicensing NOT LIKE 0)";
https://msdn.microsoft.com/en-us/library/ms190349.aspx
Evaluates the arguments in order and returns the current value of the first expression that initially does not evaluate to NULL.
Using ExecuteReader I am able to return a DataReader, but the out parameter is returning 0.
Using ExecuteNonQuery I am able to retrieve the out parameter (with the correct value) but the ExecuteNonQuery does not return a DataReader.
Here is the procedure to give context:
SQL Query:
CREATE PROCEDURE [dbo].[SelectDays]
#dateStart datetime,
#dateEnd datetime,
#recordCount bigint out
AS
BEGIN
select #recordCount = count(*)
from dbo.[Days]
where [Date]>=#dateStart and [Date]<=#dateEnd;
select [ID],[Name]
from dbo.[Days]
where [Date]>=#dateStart and [Date]<=#dateEnd;
END
Is there a way I could return a DataReader as well as the out parameter, or should I create two separate procedures for each?
C# code:
Int32 returnValue = 0;
Parameters parameters = new Parameters();
parameters.Add(new SqlParameter("#dateStart", dateStart != null ? (object)dateStart : DBNull.Value));
parameters.Add(new SqlParameter("#dateEnd", dateEnd != null ? (object)dateEnd : DBNull.Value));
SqlParameter out_recordCount = new SqlParameter("#recordCount", SqlDbType.BigInt);
out_recordCount.Direction = ParameterDirection.InputOutput;
out_recordCount.Value = recordCount;
parameters.Add(out_recordCount);
SqlParameter return_Value = new SqlParameter("#RETURN_VALUE", SqlDbType.Int);
return_Value.Direction = ParameterDirection.ReturnValue;
parameters.Add(return_Value);
dataReader = this.command.ExecuteReader("dbo.SelectDays", CommandType.StoredProcedure, parameters.ToArray());
if(out_recordCount.Value != DBNull.Value)
recordCount = Convert.ToInt64(out_recordCount.Value);
returnValue = Convert.ToInt32(return_Value.Value);
return returnValue;
The value for your output parameter is in the stream from SQLServer AFTER any results sets returned (I believe this is also true of the return value). That means you won't see the value until after you read all the rows from the DataReader (or close it I believe). So an output parameter that tells you the number of rows in the result set is of little use.
However, the code fragment below demonstrates the sequence of operations you should be using:
using(SqlConnection connection = new SqlConnection("[your connection string here]"))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.SelectDays";
command.Parameters.AddWithValue("#dateStart", dateStart != null ? (object)dateStart : DBNull.Value);
command.Parameters.AddWithValue("#dateEnd", dateEnd != null ? (object)dateEnd : DBNull.Value);
SqlParameter out_recordCount = new SqlParameter("#recordCount", SqlDbType.BigInt);
out_recordCount.Direction = ParameterDirection.InputOutput;
out_recordCount.Value = recordCount;
command.Parameters.Add(out_recordCount);
SqlParameter return_Value = new SqlParameter("#RETURN_VALUE", SqlDbType.Int);
return_Value.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(return_Value);
using(SqlDataReader reader = command.ExecuteReader())
{
while(reader.Read()) { /* do whatever with result set data here */ }
}
/* Output and return values are not available until here */
if (out_recordCount.Value != DBNull.Value)
recordCount = Convert.ToInt64(out_recordCount.Value);
returnValue = Convert.ToInt32(return_Value.Value);
return returnValue;
}
}
To get the values from OUTPUT parameters with SqlDataReader you can only after the reader will be closed.
So you need to add this code before you try to get the values
if(!dataReader.IsClosed)
dataReader.Close();
if(out_recordCount.Value != DBNull.Value)
recordCount = Convert.ToInt64(out_recordCount.Value);
returnValue = Convert.ToInt32(return_Value.Value);
public static DataTable GetBatches(long storeID, long? ProfileID)
{
string query =
"SELECT .... where " + (ProfileID.HasValue ? "PROFILE_ID=" + ProfileID.Value : "STORE_ID=" + storeID);
i want to change that query to accept parametrized values like this :
List<SqlParameter> params_list = new List<SqlParameter>();
SqlParameter param_ProfileID = new SqlParameter("#PROFILE_ID", ProfileID);
param_StoreID.SourceColumn = "PROFILE_ID";
param_StoreID.DbType = DbType.Int64;
params_list.Add(param_ProfileID);
but what if Profile_id is null ? how can i do it
Basically, you use DBNull.Value:
SqlParameter param_ProfileID = new SqlParameter("ProfileID",
(object)ProfileID ?? DBNull.Value);
And use #PROFILE_ID in the TSQL, for example:
where table.ProfileID = #ProfileID
Alternatively, use a helper tool like dapper, and forget about it:
return connection.Query<SomeType>(
"select * from SomeTable where ProfileID = #ProfileID",
new { ProfileID }).ToList();
(which returns a List<SomeType>, not a DataTable)
Re conditional searching, there are various approaches here; one is the sub-optimal:
where (#Foo is null or table.Foo = #Foo)
and (#Bar is null or table.Bar = #Bar)
which matches #Foo when it is provided, and #Bar when it is provided - but... it isn't great at hitting indexes, especially if you add more clauses. In your case, I would be tempted to do:
var sql = ProfileID == null
? "select * from Blah where StoreID = #StoreID"
: "select * from Blah where StoreID = #StoreID and ProfileID = #ProfileID";
which uses optimal TSQL for the 2 scenarios. It doesn't matter if you provide unused parameters on the command, but you could also do:
cmd.Parameters.AddWithValue("StoreID", StoreID);
if(ProfileID != null) cmd.Parameters.AddWithValue("ProfileID", ProfileID);
Based upon your comments, the query should look like this:
SELECT * FFROM tbl WHERE (#Profile_Id = NULL AND Store_Id = #Store_Id)
OR (#Profile_Id <> NULL AND Profile_Id = #Profile_Id)
You can set up the parameters like this:
List<SqlParameter> params_list = new List<SqlParameter>();
SqlParameter param_ProfileID = new SqlParameter("#PROFILE_ID", (object)ProfileID ?? DBNull.Value);
param_StoreID.SourceColumn = "PROFILE_ID";
params_list.Add(param_ProfileID);
SqlParameter param_StoreID = new SqlParameter("#STORE_ID", StoreId);
param_StoreID.SourceColumn = "STORE_ID";
params_list.Add(param_StoreID);
you can use this work around
List<SqlParameter> params_list = new List<SqlParameter>();
if(ProfileID==null)
{
SqlParameter param_ProfileID = new SqlParameter("#PROFILE_ID", DBNull.Value);
}
else
{
SqlParameter param_ProfileID = new SqlParameter("#PROFILE_ID", ProfileID);
}
param_StoreID.SourceColumn = "PROFILE_ID";
param_StoreID.DbType = DbType.Int64;
params_list.Add(param_ProfileID);
Looking at your first example, it seems clear that you don't need to build a parameter if your profileID variable is null, simply you write a different query
public static DataTable GetBatches(long storeID, long? ProfileID)
{
List<SqlParameter> pList = new List<SqlParameter>();
string query = "SELECT .... where ";
if(ProfileID.HasValue)
{
query += "PROFILE_ID= #proID";
SqlParameter pProfileID = new SqlParameter("#proID", SqlDbType.BigInt)
.Value = ProfileID.Value;
pList.Add(pProfileID);
}
else
{
query += "STORE_ID= #stoID";
SqlParameter pStoreID = new SqlParameter("#stoID", SqlDbType.BigInt)
.Value = storeID;
pList.Add(pStoreID);
}
If ProfileID is not null you search for it otherwise you search for StoreID and that's all.
I was trying to handle DbNull exception like this:
string sql_com_sumcastka = "SELECT SUM(price) AS sumprice FROM kliplat WHERE akce='" + zakce.Text + "' AND year=" + year;
SqlCommand sc2 = new SqlCommand(sql_com_sumprice, spojeni);
spojeni.Open();
if (sc2 != DBNull.Value)
{
int result = Convert.ToInt32(sc2.ExecuteScalar());
}
else
{
int result = 0;
}
spojeni.Close();
string sql_com_update_sum = "UPDATE zajezd SET s_prijmy=#s_prijmy WHERE akce='"+zakce.Text+"' AND year="+year;
SqlCommand sc3 = new SqlCommand(sql_com_update_sum,spojeni);
sc3.Parameters.AddWithValue("#s_prijmy", result );
spojeni.Open();
sc3.ExecuteNonQuery();
spojeni.Close();
But as I don't know how to properly handle if result is DBNull I get this erros: Operator '"=' cannot be applied to operands of type system.Data.SqlClient.SqlCommand and System.Dbnull
and
The name 'result' does not exist in the current context
My problem is this line of code:
if (sc2 != DBNull.Value)
{
int result = Convert.ToInt32(sc2.ExecuteScalar());
}
else
{
int result = 0;
}
Thanks for helping.
ExecuteScalar doesn't return DBNull (unless..., please read comments below) but null and you need to test the return value of ExecuteScalar not the SqlCommand that executes the command
int sumOfPrice = 0;
object result = sc2.ExecuteScalar();
if(result != null)
sumOfPrice = Convert.ToInt32(result);
From MSDN
ExecuteScalar returns the first column of the first row in the result
set, or a null reference (Nothing in Visual Basic) if the result set
is empty.
As a side note, do not use string concatenation to build a command text to pass to your database. You risk Sql Injection and parsing erroros. Use instead a parameterized query like this
string sql_com_sumcastka = "SELECT SUM(price) AS sumprice FROM kliplat " +
"WHERE akce=#zak AND year=#year";
SqlCommand sc2 = new SqlCommand(sql_com_sumprice, spojeni);
sc2.Parameters.AddWithValue("#zak", zakce.Text);
sc2.Parameters.AddWithValue("#year", year);
Here is the correct way to do that
var objResult = sc2.ExecuteScalar();
if (objResult != DBNull.Value && objResult != null )
{
int result = (int)objResult; //you can just do a normal cast, "SUM(X)" returns a int.
}
else
{
int result = 0;
}
A SqlCommand can never be compared to DBNull.Value in your example. What it sounds like you want is to check the result of your execute scalar invocation to see if that is null:
var result = sc2.ExecuteScalar();
if(result as DBNull == null)
{
// value is not null, do processing
}
I know the answer is late but this is the simplest answer that I have found
SELECT (SUM(price),0) FROM kliplat
If the result is null it will be replaced with 0