comma vs point in double with an access database - c#

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.

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 });

ColumnSize of numeric is not same original (c#)(dBase)

I want to get a database schema (dBase), so I use "oledb" to get data from a dbase file for using getchemaTable to get the schema of data, but the "ColumnSize" of the numeric data type excludes "19". As the original data, such as "object_id" Type: nummeric column size: 12, but it returns the output to "19".
I want to show the results to the exact same. but..
I don't know what to do next.
public static DataSet getStructureDBF(string dir, string input)
{
OleDbConnection objConn = new OleDbConnection(#"Provider=VFPOLEDB.1;Data Source=" + dir + ";Persist Security Info=False;");
objConn.Open();
OleDbCommand objCmd = new OleDbCommand("Select * from " + input, objConn);
OleDbDataReader objDataReader = objCmd.ExecuteReader();
DataTable schemaTable = objDataReader.GetSchemaTable();
DataSet dsnew = new DataSet();
dsnew.Tables.Add(schemaTable);
return dsnew;
}
For all data types, dBASE field definitions store field length and precision. The latter is only relevant for numeric types, and the former is the maximum number width in digits, because that is how dBASE stores numbers: actual strings of digits.
See dbf file format specification
Edit
Note that data types Numeric and Float are stored as strings of digits. Number types in more recent versions of dBASE are stored as binary values.
Also see DBF reader implementation notes

Incorrect string value: '\xEF\xBF\xBD' for column

I have a table I need to handle various characters. The characters include Ø, ® etc.
I have set my table to utf-8 as the default collation, all columns use table default, however when I try to insert these characters I get error: Incorrect string value: '\xEF\xBF\xBD' for column 'buyerName' at row 1
My connection string is defined as
string mySqlConn = "server="+server+";user="+username+";database="+database+";port="+port+";password="+password+";charset=utf8;";
I am at a loss as to why I am still seeing errors. Have I missed anything with either the .net connector, or with my MySQL setup?
--Edit--
My (new) C# insert statement looks like:
MySqlCommand insert = new MySqlCommand( "INSERT INTO fulfilled_Shipments_Data " +
"(amazonOrderId,merchantOrderId,shipmentId,shipmentItemId,"+
"amazonOrderItemId,merchantOrderItemId,purchaseDate,"+ ...
VALUES (#amazonOrderId,#merchantOrderId,#shipmentId,#shipmentItemId,"+
"#amazonOrderItemId,#merchantOrderItemId,#purchaseDate,"+
"paymentsDate,shipmentDate,reportingDate,buyerEmail,buyerName,"+ ...
insert.Parameters.AddWithValue("#amazonorderId",lines[0]);
insert.Parameters.AddWithValue("#merchantOrderId",lines[1]);
insert.Parameters.AddWithValue("#shipmentId",lines[2]);
insert.Parameters.AddWithValue("#shipmentItemId",lines[3]);
insert.Parameters.AddWithValue("#amazonOrderItemId",lines[4]);
insert.Parameters.AddWithValue("#merchantOrderItemId",lines[5]);
insert.Parameters.AddWithValue("#purchaseDate",lines[6]);
insert.Parameters.AddWithValue("#paymentsDate",lines[7]);
insert.ExecuteNonQuery();
Assuming that this is the correct way to use parametrized statements, it is still giving an error
"Incorrect string value: '\xEF\xBF\xBD' for column 'buyerName' at row 1"
Any other ideas?
\xEF\xBF\xBD is the UTF-8 encoding for the unicode character U+FFFD. This is a special character, also known as the "Replacement character". A quote from the wikipedia page about the special unicode characters:
The replacement character � (often a black diamond with a white question mark) is a symbol found in the Unicode standard at codepoint U+FFFD in the Specials table. It is used to indicate problems when a system is not able to decode a stream of data to a correct symbol. It is most commonly seen when a font does not contain a character, but is also seen when the data is invalid and does not match any character:
So it looks like your data source contains corrupted data. It is also possible that you try to read the data using the wrong encoding. Where do the lines come from?
If you can't fix the data, and your input indeed contains invalid characters, you could just remove the replacement characters:
lines[n] = lines[n].Replace("\xFFFD", "");
Mattmanser is right, never write a sql query by concatenating the parameters directly in the query. An example of parametrized query is:
string lastname = "Doe";
double height = 6.1;
DateTime date = new DateTime(1978,4,18);
var connection = new MySqlConnection(connStr);
try
{
connection.Open();
var command = new MySqlCommand(
"SELECT * FROM tblPerson WHERE LastName = #Name AND Height > #Height AND BirthDate < #BirthDate", connection);
command.Parameters.AddWithValue("#Name", lastname);
command.Parameters.AddWithValue("#Height", height);
command.Parameters.AddWithValue("#Name", birthDate);
MySqlDataReader reader = command.ExecuteReader();
...
}
finally
{
connection.Close();
}
To those who have a similar problem using PHP, try the function utf8_encode($string). It just works!
I have this some problem, when my website encoding is utf-u and I tried to send in form CP-1250 string (example taken by listdir dictionaries).
I think you must send string encoded like website.

SQL C# Doubles with decimals

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.

Categories