SQL C# Doubles with decimals - c#

I'm trying to enter a double value in an SQL update statment, which is already converted (see code 1), to keep his numbers behind the comma.
(1)
double.TryParse(splitline[8], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out natMB //conversion
(2) Putting my value in an procedure to my SQL statement, i putted natMB into 'Verbruikgegevens', index position 2. 0 or 1 indicates if my inputted data is roaming or not. This is a part of an if statement declaring weither it's roaming or national data.
sqlStatementUpdate(TrafficdataID, 0,
(Convert.ToDouble(Verbruikgegevens.Rows[intCount].ItemArray[2],
CultureInfo.InvariantCulture))
(3) SQL statement in Visual studio (C#)
public void sqlStatementUpdate(long TrafficdataID, byte Roaming, double Value)
{
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.Connection = connection2;
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd.CommandText = "SP_SCTrafficdataDetailUpdate";
DataAccessHelper.AddParam(sqlCmd, "TDDValue", SqlDbType.Decimal, Convert.ToDecimal(Value));
DataAccessHelper.AddParam(sqlCmd, "TrafficdataID", SqlDbType.BigInt, TrafficdataID);
DataAccessHelper.AddParam(sqlCmd, "TDDRoaming", SqlDbType.Bit, Roaming);
DataAccessHelper.ExecSProcDS(sqlCmd);
}
(4) DataAccesHelper
internal static class DataAccessHelper
{
public static void AddParam(SqlCommand cmd, string columnName, SqlDbType dbType, object paramvalue)
{
if (paramvalue is DateTime)
{
if (((DateTime)paramvalue).Date == DateTime.MinValue.Date)
{
paramvalue = DBNull.Value;
}
}
if (paramvalue == null)
{
paramvalue = DBNull.Value;
}
string param = "#" + columnName;
if (!cmd.Parameters.Contains(param))
{
if (dbType == SqlDbType.VarChar || dbType == SqlDbType.NVarChar || dbType == SqlDbType.Char || dbType == SqlDbType.NChar)
cmd.Parameters.Add(param, dbType, 4000);
else
cmd.Parameters.Add(param, dbType);
cmd.Parameters[param].SourceColumn = columnName;
cmd.Parameters[param].Value = paramvalue;
}
}
public static DataSet ExecSProcDS(SqlCommand cmd)
{
DataSet ds = new DataSet();
try
{
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
da.Fill(ds);
}
catch (Exception ex)
{
throw (ex);
}
return ds;
}
(5) SQL statement
ALTER PROCEDURE [dbo].[SP_SCTrafficdataDetailUpdate] #TDDValue decimal, #TrafficdataID bigint, #TDDRoaming bit
AS
BEGIN
UPDATE TR_SCTrafficDataDetail
SET TDDValue = #TDDValue
WHERE (TDDType = 'Data') AND (TrafficDataID = #TrafficdataID) AND (TDDRoaming = #TDDRoaming)
END
QUESTION: Is it possible that I keep using a double, and also keep my numbers behind the comma when importing the data to my sqltable? Right now it doesn't seem to work that wel ... I defined my Value in my SQLTable as an decimal though

So the question is:
I have text input representing numbers, using sometimes a comma and sometimes a period for the decimal separator. How can I convert these reliably to numbers?
Answer: This has nothing to do with the SQL data types. You need to first write reliable C# code to convert the number to a double or decimal. Either will do - you should use whichever one matches your database.
The Invariant culture REQUIRES the period as a decimal point, NOT the comma. So you are using the wrong culture if you have commas as decimal separator.
If you know what format your numbers are in, use the overloaded Parse and specify the format directly.
If it is from user input, use the user's culture, OR train the user what format to use.
Finally, if you have some odd format, you might need to write your own code to regularise the format using regexes.
Speed issues
10000 rows is nothing it should take seconds not minutes.
I notice you are creating a new SqlCommand for each row. Each time you do so it has to go to the SQL server and match up the metadata with the stored proc you are calling.
Just create it once, and re-use it by setting the values to the values from the new row. Just don't forget to set the NULL ones to DBNull.Value.

Related

Decimal after two digit should contain 0 at second place should not be omitted

i am trying to round off value to two decimal places. but the issue is 0 at second is not appearing , it only shows decimal after one place.
i have fetched data from oracle db as 180.700 but while fetching it from db it shows only 180.7 in datatable after binding
using (OracleConnection con = new OracleConnection(constr_ipdmdm))
{
using (OracleCommand cmd = new OracleCommand(query))
{
using (OracleDataAdapter sda = new OracleDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
}
}
}
}
while rounding it off to two decimal places it shows only one value after decimal i.e 180.7
Math.Round(Convert.ToDecimal(dt_spec.Rows[2]["YS"]), 2)
how can we show as 180.700 while binding it in datatable
and how can we round it two two decimal place i.e 180.70
Any idea would be appreciated.
You can get oracle to round and format it
TO_CHAR(numbercolumn, 'FM999990D00')
This converts to a string in oracle so your c# app will receive a string. If you need to work with it numerically in c# you could have oracle round it instead
ROUND(numbercol, 2)
But depending on what you're doing it may be best to leave the precise decimals on and do all your work with it then format it at the end of the work
calculatedResult.ToString("0.00")
$"{calculatedResult:0.00}"
string.Format("{0:0.00}", calculatedResult)
You don't need to Math.Round it first. Formatting 1.2355 as "0.00" becomes "1.24"
If you're using this datatable of yours in something like a windows forms DataGridView then it's the job of the grid to format the data, not on you to change it to a string. Look at something like
TheDgv.Columns[TheColumnIndex].DefaultCellStyle.Format = "0.00";
And make sure the data in the datatable column is numeric, not a string
Preface: I know nothing about C#. I do have a logic suggestion though! Consider interpreting/casting the number as a string/chararray, and concatenating a bunch of zeros to the end of the string. Then, cast back to floating point, and do the roundoff. There should be another zero there.
I'm not very familiar with the functions being used, but this logic has worked in the past in other languages.

SqlCommand with parameters accepting different data formats

Imagine this code:
string value = "1.23";
string query = "UPDATE MYTABLE SET COL1=#p1";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("#p1", value);
cmd.ExecuteNonQuery();
On my database it will work with value="1.23" if COL1 is decimal type column. But it will fail if value is "1,23" (comma instead of a dot as a decimal point). The error is
Error converting data type nvarchar to numeric
I'd like it to work in both cases with "value" being a string variable.
Unfortunately I cannot just replace comma for the dot as this code is going to be more universal, dealing both with numeric and varchar columns
Is there any way that an query accepts a parameter with number written as a string both with dot and a comma and correctly puts it in into table?
Thanks for any help
If the value isn't semantically a string, you shouldn't send it as a string. The type of the parameter value is important, and influences how it is transmitted and can lead to culture issues (comma vs dot, etc).
If the value is semantically a decimal, then use something like:
string value = "1.23";
var typedValue = decimal.Parse(value); // possible specifying a culture-info
//...
cmd.Parameters.AddWithValue("#p1", typedValue);
Then it should work reliably.
Unrelated, but you can make ADO.NET a lot easier with tools like "Dapper":
connection.Execute("UPDATE MYTABLE SET COL1=#typedValue", new { typedValue });

comma vs point in double with an access database

In my C# program, I use a strongly typed dataset with an access database. In one table of the DB, I use a double. With some cultures, access uses a comma instead of a point for a double value. I can read the value without a problem (IE if access uses a comma: "10,25" is read as a "10.25" double value). But when I want to insert a new value, I get an exception if access uses a comma and one of the values is a decimal (IE "10" is insert, "10.25" throw the exception). The exception is thrown when I update the DB, not when I create a new row in the dataset.
As I use a dataset, I thought that these problems were automatically handled by .Net.
How can I manage comma/point (I think I must get the culture of the user, then force the dataset to use it. But how?)?
PS : I can't change the computer culture, so I need to manage all cultures by code.
Note that doubles do not contain commas or points. They store the number in a binary representation internally using a mantissa and an exponent. The comma vs point issue only comes into play if you have a string representation of the double (most likely a sql string).
Do not write:
// Here the double is in a string
string sql = "INSERT INTO mytable (id, value) VALUES (1, 10.25)";
using (OleDbCommand cmd = new OleDbCommand(sql, conn)) {
cmd.CommandType = CommandType.Text;
conn.Open();
cmd.ExecuteNonQuery();
}
Instead use command parameters:
// Here the double is never converted to a string
string sql = "INSERT INTO mytable (id, value) VALUES (?, ?)";
using (OleDbCommand cmd = new OleDbCommand(sql, conn)) {
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("?", 1);
cmd.Parameters.AddWithValue("?", 10.25);
conn.Open();
cmd.ExecuteNonQuery();
}
Of course, in the C# code the double is written in a textual representation. However, when compiled and at runtime the double exists in its pure binary form, not remembering the character of the decimal separator used in the code.

Invalid argument error in c#

I am running into the following problem. I don't know what i'm doing wrong. It shows me an error "The best overloaded method match for 'System.Data.Common.DbDataReader.GetString(int)' has some invalid arguments."
Here is my code:
SqlDataReader myReader;
mycon.Open();
myReader = cmdDatabase.ExecuteReader();
while (myReader.Read())
{
string cName = myReader.GetString("C_Name");
textBox2.Text=cName;
}
The GetString method only accepts an int. You're passing it a string.
From MSDN, the parameter (an integer) represents "the zero-based column ordinal."
If C_Name is the first column (for example), you'd want to call:
string cName = myReader.GetString(0);
As has been mentioned several times now, the signature of GetString requires an integer representing the column index. You can translate the column name to its ordinal position using GetOrdinal.
Therefore, you can get the string value of the "C_NAME" column by using myReader.GetString(myReader.GetOrdinal("C_NAME")).
SqlDataReader also overrides the indexer, which lets you write the same as (string)myReader["C_Name"]
Complete example:
var sqc = new SqlCommand("SELECT C_NAME from table", con);
using (var reader = sqc.ExecuteReader())
{
while (reader.Read())
{
int ordinal = reader.GetOrdinal("C_NAME");
string byOrdinal = reader.GetString(ordinal);
string byIndexer = (string)reader["C_NAME"];
Console.Writeline("Column {0}, has the value of {1} (which is the same as {2})",
ordinal, byOrdinal, byIndexer);
}
}
You should also be careful to wrap your readers in using statements to ensure you don't leak database connections or run into a case where you consider enabling MARS.
Look at the signature of GetString():
System.Data.Common.DbDataReader.GetString(int)
It takes an integer ordinal (i.e. zero-based position) and you are trying to pass a string. There are no overloads which take a single string parameter.
As the error indicates, you are trying to use an overload of the GetString which does not exist.
You are passing a string argument, while the method is expecting an integer that represents the index of the requested column.
You can read more about the method in the dcumetnation
Try changing your code to something like:
int indexOf cNameIdx = 5;// replace this with the real index from your select query
string cName = myReader.GetString(cNameIdx );

C# SQL Aggregate ExecuteScalar Return Query

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.

Categories