C# SQL Aggregate ExecuteScalar Return Query - c#

An SQL aggregate function counting number of name enteries in DB.
string cnnStr = ConfigurationManager.ConnectionStrings["LGFConnectionString"].ConnectionString;
string mySQL = "SELECT COUNT(*) FROM " + which.table + " WHERE " + which.column + " = ?pram;";
string value = null;
using (MySqlConnection cnn = new MySqlConnection(cnnStr))
{
using (MySqlCommand cmd = new MySqlCommand(mySQL, cnn))
{
MySqlParameter param = new MySqlParameter("?pram", MySqlDbType.VarChar, 128);
param.Value = which.text;
cmd.Parameters.Add(param);
cnn.Open();
value = cmd.ExecuteScalar() as string;
value = cmd.ExecuteScalar().ToString();
cnn.Close();
}
}
Notice that I have called cmd.ExecuteScalar twice. Interesting part is that the query returns different results.
value = cmd.ExecuteScalar() as string;
doesn't return the correct value. It returns null for both if name is present or missing in the name column.
value = cmd.ExecuteScalar().ToString();
returns correctly. This returns "1" if present and "0" if missing.
In searching the web, I haven't found an understandable explanation.
I have read that if name is missing from name column, then cmd.ExecuteScalar will return null.
What is the difference between:
value = cmd.ExecuteScalar() as string;
value = cmd.ExecuteScalar().ToString();
Thank you,
deDogs

as in docs
The as operator is used to perform conversions between compatible types.
The as operator is like a cast except that it yields null on conversion failure instead of raising an exception
// if cmd.ExecuteScalar() is string then return string
// if not then return null
// this will return null, because cmd.ExecuteScalar() won't return string
// for your code it should return Int32
value = cmd.ExecuteScalar() as string;
ToString() in docs
ToString is the major formatting method in the .NET Framework. It
converts an object to its string representation so that it is suitable
for display. (For information about formatting support in the .NET
Framework, see Formatting Types.)
// return a string that represents the current object
// will return correct value because it casts Int32 value to string value
value = cmd.ExecuteScalar().ToString();

The 'as' keyword will return null if the objects type does not match what you are attempting to cast it to.
What is happening in your case is that the returned object is an int and when you call toString on this, it will give you a string representation of the integer. When you use as against it, it gives you a null.

You are doing two different things above. Let's change your code to the following:
decimal value = cmd.ExecuteScalar();
string str1 = value as string;
string str2 = value.ToString();
str1 will be null because decimal cannot be cast to a string.
str2 will be the value because you can call ToString() on a decimal.

Related

How to get number value with Decimal from DataReader

According to the SQL queries below, I need to get a number value 2083.10, but when try to use the code to get int value from dbreader, it will be only 2083. the demical were gone.
string SQLCash = #"SELECT sum(t2.Cash-Change) AS Cash
FROM dbFBHdr t1, dbFBCollection t2
WHERE t1.Branch = t2.Branch
AND t1.CashNo = t2.CashNo
AND t1.CashDate >= '" + PDC.DateFrom + "' " +
"AND t1.CashDate <= '" + PDC.DateTo + "' " +
"AND t1.Status = 'CLOSED'";
FbCommand cmdCASH = new FbCommand(SQLCash, FbCon);
cmdCASH.ExecuteNonQuery();
FbDataReader readerCASH = cmdCASH.ExecuteReader();
while (readerCASH.Read() == true)
{
if (readerCASH["Cash"].ToString() == "")
{
PDC.CASH = "0";
}
else
{
PDC.CASH += String.Format("{0:n}",readerCASH["Cash"]);
PDC.TOCASH = readerCASH.GetInt32(readerCASH.GetOrdinal("Cash"));
}
}
And This is the code which I use it to get Int value from SQL
PDC.TOCASH = readerCASH.GetInt32(readerCASH.GetOrdinal("Cash"));
Since you need to Gets the value as a Decimal object, You need to use SqlDataReader.GetDecimal(Int32) method instead:
readerCASH.GetDecimal(readerCASH.GetOrdinal("Cash"));
Because the GetInt32 method will get the value as a 32-bit signed integer. Also you need to change the TOCASH's type to decimal. Also you should always use parameterized queries to avoid SQL Injection. Something like this:
AND t1.CashDate >= #DateFrom
yourCommand.Parameters.AddWithValue("#DateFrom", PDC.DateFrom);
//And other parameters also
Although specify the type directly and use the Value property is better than AddWithValue. See this https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
Don't use GetInt32 if you want to get value as decimal, use GetDecimal
PDC.TOCASH = readerCASH.GetDecimal(readerCASH.GetOrdinal("Cash"));
You are formatting it to be without commas so it will be return as it is integer
PDC.CASH += String.Format("{0:n2}",readerCASH["Cash"]);
n2 means 2 digits after comma also i suggest you to use {0:c2} if you are working with currency
If you not sure to which .Net type will be mapped initial RDBMS one (e.g. Number(16, 4) -> ? will it be Single, Double or Decimal?) you can try converting:
decimal result = Convert.ToDecimal(readerCASH["Cash"]);

Convert.ToString returns string.empty instead of null

I've found out a strange behaviour of Convert.ToString and I would like to understand, why it does behave like this.
Have a look at following code pieces:
string obj = null;
var str = Convert.ToString(obj);
Console.WriteLine(str); // CORRECT: returns null;
all good so far, but:
DBNull obj = DBNull.Value;
var str = Convert.ToString(obj);
Console.WriteLine(str); // ???: returns string.Empty ("")
and
object obj = null;
var str = Convert.ToString(obj);
Console.WriteLine(str); // ???: returns string.Empty ("")
It looks to me like a bug, because when i do a conversion to a string and the input is NULL the result should be default of a string, which is also NULL.
Convert.ToString has a String overload that does nothing:
Returns the specified string instance; no actual conversion is performed.
and its Object overload is defined thus:
The string representation of value, or String.Empty if value is null.
It might be a bit surprising, but there’s no reason to use Convert.ToString on a String expression in the first place.
That's documented behaviour
Convert.ToString Method (Object)
The string representation of value, or String.Empty if value is null.
Convert.ToString Method (String)
value is returned unchanged.

Trying to check if int value is indeed an int

I'm trying to check a passed variable to ensure that it is indeed of type Int. However, I keep having an error appear that tells me that the variable "year" cannot be converted from an int to a string. I'm stuck because I'm not trying to convert it over so I'm confused as to what I'm missing.
[HttpGet("[action]")]
[Authorize]
public ListResult ProblemsYTD(int year = "")
{
var sql = "SELECT DatePart(yyyy, CLL.Call_Log_Date) as [ProblemsYear], CLL.Service as [Service], Sum((DATEDIFF(dd, CLL.Call_Log_Date, GetDate()))) as [DaysOpen] " +
"FROM VMWareSM_Test.dbo.RV_CALL as CLL " +
"Where CLL.IPK_Stream_Ref = '19' And DatePart(yyyy, CLL.Call_Log_Date)";
int myInt;
if (!int.TryParse(year, out myInt))
{
year = "%" + year + "%";
sql += " = #year";
}
sql += " Group by CLL.Service, DatePart(yyyy, CLL.Call_Log_Date) "+
"Order by CLL.Service DESC; ";
SqlParameter[] sqlParams =
{
new SqlParameter
{
ParameterName = "#year",
Value = year,
DbType = DbType.Int32,
Direction = ParameterDirection.Input
}
};
Let's start from your use of the variable year. It is used as part of a where condition where also a DatePart function call is involved. Now DataPart returns an integer so you need an integer for your checks, not a string.
At this point your declaration of the method should be simple an integer without a default value or you could use a default value of zero.
You cannot use an empty string as default value for an integer. C# doesn't allow this free implicit conversions between types like an Option Strictless VB.NET
So the call should be simply
public ListResult ProblemsYTD(int year = 0)
at this point all the code that checks if the caller has passed an integer is useless because the caller cannot pass any other kind of type or value. Just integers or types that can be cast to an integer without loosing information (byte, short but not long) You declare the method to receive an integer and the compiler blocks any different type with a compilation error.
However you could add a check for a reasonable value for your year variable.
For example you could limit the upper and lower values with something like this
if (year >= 2000 && year <= DateTime.Today.Year)
{
sql += " = #year";
}
Note that you cannot concatenate a "%" symbol to an integer for the same reason that you cannot assign an empty string to an integer.
Your function should be declared like this
public ListResult ProblemsYTD(string year = "")
{
...
}
also year = "%" + year + "%";
make no since the % is used in LIKE statements
should be something like this :
if (int.TryParse(year, out myInt))
{
sql += " = #" + year;
}
else
{
throw new Exception("Year is not in correct format");
}
This line looks fishy:
public ListResult ProblemsYTD(int year = "")
You're providing an empty string ("") as the default value for year. I think you mean to have the parameter be a string when it is passed in.
public ListResult ProblemsYTD(string year = "")
I'm trying to check a passed variable to ensure that it is indeed of type Int.
Most likely you just need to use a Route Constraint
Example Route:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"}
);
Controller:
public class ProductController : Controller
{
public ActionResult Details(int productId)
{
return View();
}
}
with the following producing an error:
/Product/blah
/Product/apple
You can add a route constraint to only route to the controller/action if it is an int:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"},
new {productId = #"\d+" }
);
This means that your controller is not in charge of type checking (it probably shouldn't anyway) and you can create a another route to catch non-ints and display a different view accordingly.
int year = ""
You cannot set an integer variable to a string value.

C# conversion issue from a generic value to string

I am facing quite an odd issue,....
I have got a code which reads XML and converts each value irrespective of what type it is for example, int, float, double or a String it self to a String value and then stores it into a String variable.
String column = System.Convert.ToString(values.GetValue(rowNum, colNum))
problem I have is, lets say if "values.GetValue(rowNum, colNum)" returns 0.000003825, then when ran, the value that gets converted and stored in "column" is "3.825E-06" which is in scientific notation which I do not really want,
I want "column" to store value 0.000003825 in string format, how do I do that?
thanks
You will need to supply formatting information. Unfortunately, you can't supply formatting information to System.Convert.ToString(). Instead, you must call string.Format() or object.ToString().
For example:
double value = 0.000003825;
string s1 = value.ToString("0.################");
Console.WriteLine(s1);
string s2 = string.Format("{0:0.################}", value);
Console.WriteLine(s2);
Try ToString() to convert it to object
OK, I have fixed this now..
It works a treat irrespective of what the type of value we pass through obj,
thanks.
Object obj = -0.00002357467;
String value = obj.ToString();
String type = obj.GetType().ToString();
if (type.Equals("System.Double")&&value.Contains("E-"))
{
double doubleValue = (double)obj;
value = doubleValue.ToString("0.############################"); //thanks #Matthew Watson
}
Console.WriteLine(value); //prints -0.00002357467

Passing null into a DataTable from a single line conditional statement parsing string values

I have an app that loops through a fixed width text file, reads each line into a string variable and uses the .Substring() method to find data for a given field. For a given field, it checks to see if the contents are simply spaces, or if there is actually "data" in it, i.e. anything but spaces. If there is data, and that data represents a date, for instance, then DateTime.Parse() is run on that data and passed to a field of type datetime in a C# DataTable; however, if there is no data--just spaces, I want to simply pass a null value to the field. Here is a snippet of code to illustrate:
var dataTable = new DataTable();
dataTable.Columns.Add("Application_Date").DataType = Type.GetType("System.DateTime");
while (!sr.EndOfStream)
{
string row = sr.ReadLine();
if (row.Substring(0, 1) == "2" && row.Substring(42, 1) == "T")
{
DataRow dr = dataTable.NewRow();
dr["Application_Date"] = row.Substring(124, 8) != " " ?
DateTime.Parse(row.Substring(124, 4) +
"-" + row.Substring(128, 2) + "-" +
row.Substring(130, 2)) :
null as DateTime?;
}
}
My problem is that when I try to run this, it throws an error saying it wants a DBNull (Cannot set Column 'Application_Date' to be null. Please use DBNull instead.)
But when I attempt to simply pass a DBNull instead, it tells me that it can't convert between DateTime and DBNull (Type of conditional expression cannot be determined because there is no implicit conversion between 'System.DateTime?' and 'System.DBNull')
What am I missing here?
You need to cast the DateTime to object to use it in the conditional:
dr["Application_Date"] = (...) ? (object)DateTime.Parse(...) : DBNull.Value;
Using the null-coalescing operator:
dr["Application_Date"] = (object)nullableDateTime ?? DBNull.Value;

Categories