Failed to convert parameter value from a String to a Decimal - c#

Im importing a csv to my sql server table using the following code
SqlCommand nonqueryCommand = myConnection.CreateCommand();
nonqueryCommand.CommandText =
"INSERT INTO MYTABLE VALUES(#num1, #num2,#num3,#num4)";
nonqueryCommand.Parameters.Add("#num1",SqlDbType.Decimal);
nonqueryCommand.Parameters.Add("#num2", SqlDbType.Decimal);
nonqueryCommand.Parameters.Add("#num3", SqlDbType.Decimal);
nonqueryCommand.Parameters.Add("#num4", SqlDbType.Decimal);
nonqueryCommand.Parameters["#num1"].Value = crntRecord[0];
nonqueryCommand.Parameters["#num2"].Value = crntRecord[1];
nonqueryCommand.Parameters["#num3"].Value =crntRecord[3];
nonqueryCommand.Parameters["#num4"].Value = crntRecord[4];
nonqueryCommand.ExecuteNonQuery();
where the parameter 3 and 4 are of type decimal(9,6) in the DDL when i execute the code at ExecuteNonQuery i get the following exception
Failed to convert parameter value from a String to a Decimal.
please help me find out the problem tnx.
EDIT
the value in the crntRecord[3] looks like

Assuming that crntRecord is an array of strings, you need to parse the strings to a decimal first.
Ex:
nonqueryCommand.Parameters["#num3"].Value = decimal.Parse(crntRecord[3].ToString());
Note that this will throw an exception if crntRecord[3] is not parseable to a decimal; if that's a situation that could occur, look into decimal.TryParse() instead.

Edited to use safer parsing methods
Your strings have surrounding quotes that you need to strip off. Try
decimal num3;
bool isDecimal = decimal.TryParse(crntRecord[3].Trim(new []{'\"'}), out num3);
if(isDecimal)
nonqueryCommand.Parameters["#num3"].Value = num3;
I would recommend using this method for all of your decimals, which would mean putting this logic in a reusable function would be a rise refactoring.

try with
nonqueryCommand.Parameters["#num1"].Value = Convert.ToDecimal(crntRecord[0]));
nonqueryCommand.Parameters["#num2"].Value = Convert.ToDecimal(crntRecord[1]);
nonqueryCommand.Parameters["#num3"].Value =Convert.ToDecimal(crntRecord[3]);
nonqueryCommand.Parameters["#num4"].Value = Convert.ToDecimal(crntRecord[4]);

Use
nonqueryCommand.Parameters.AddWithValue("#num1", crntRecord[0]);

Related

name variable from oracle sql string value in c#

This is my first project in c#. I have a little experience in Access VBA. I would like to move my apps over to be stand alone programs. I'm querying a table that has training types and dates. I would like to compare some of the types of training against each other based on the dates they were performed. The three training types are RWT010, RWP000, and RWT010BP. If RWT010BP exists and is newer it is the only one I need. Otherwise I need RWT010 and RWP000. I have figured out how to load the values into variables, but I need to be able to work with them. I would like the name of the dateTime value to be the trainType for the same row. That way I can compare them and output the right combination.
My old Access logic looked like this:
LABEL_DATE: IIf(IsNull([RWT010]),"RWT010BP: " & _
Format([RWT010BP],"Short Date"),IIf([RWT010BP]>[RWT010],"RWT010BP: " & _
Format([RWT010BP],"Short Date"),"RWT010: " & _
Format([RWT010],"Short Date") & " & " & "RWP000: " & _
Format([RWP000],"Short Date")))
This is how far I've gotten in c#:
Console.Write("Enter ID: ");
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
It looks like the original Access logic has one DB row with three date fields, [RWT010], [RWT010BP], and [RWP000]. But in Oracle that's been normalized so you're getting back multiple rows, each of which has a a datetime field named [DATE_LATEST], and then name field called [TYPE] that's equal to "RWT010", "RWT010BP", or "RWP000".
And you were thinking, you want to handle those RWP000 date values by name, just like in Access. You were right, that's the clearest way to do it, and I'll show you how. I misunderstood what you were asking.
One way to do this would be to write an Oracle stored procedure that duplicates the Access logic. That's not the question you asked, but it's a legitimate way to do it. However, it would be more complicated than the Access version due to the change in the database, and anyway I haven't written Oracle SQL in years and I don't have an Oracle server handy to give me arbitrary, cryptic syntax errors about semicolons and whitespace.
So what I'm going to do is write a loop in C# to grab the datetimes from the DB rows and put them in local variables, and then duplicate the Access logic in C# using those variables instead of fields. It'll be a little verbose compared to the Access version, but sometimes that's how it goes.
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
// I don't know how you're using this so I'll just declare it here
// and leave that to you.
String dateLabel = "";
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
DateTime? RWT010 = null;
DateTime? RWT010BP = null;
DateTime? RWP000 = null;
// No need to check reader.HasRows. If it has no rows, reader.Read()
// will return false the first time, that's all.
while (reader.Read())
{
// Doesn't look to me like expid is used
//int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
switch (trainType) {
case "RWT010":
RWT010 = trainDate;
break;
case "RWT010BP":
RWT010BP = trainDate;
break;
case "RWP000":
RWP000 = trainDate;
break;
}
}
if (RWT010 == null || RWT010BP > RWT010) {
dateLabel = String.Format("RWT010BP: {0:d}", RWT010BP);
} else {
dateLabel = String.Format("RWT010: {0:d} & RWP000: {1:d}", RWT010, RWP000);
}
}
The original logic was this:
If RWT010 isn't null,
Do A
Otherwise, if RWT010BP > RWT010
ALSO do A
But if none of the above,
Do B
The first two branches do the exact same thing, so we can condense them both into one branch.
"Don't Repeat Yourself", as they say. You don't want to return to this code a year from now, wonder if those two lines were required to be the same, and then guess wrong or else not notice that they are the same, and only change one or the other. It's just a mess.
If you're not familiar with String.Format(), there's a lot to it. In the first argument string, {0} means "insert the second argument here"; {1} means "insert the third", and so on. The ":d" inside the curly braces is optional; it means to pass "d" as format information to the value its inserting. DateTime will interpret that "d" to mean "Short Date". You could also do it like this:
dateLabel = String.Format("RWT010BP: {0}", RWT010BP.Value.ToShortDateString());
Or like this:
dateLabel = "RWT010BP: " + RWT010BP.Value.ToShortDateString();
I have to use RWT010BP.Value in that line instead of just RWT010BP because RWT010BP is declared with a ? after it. That makes it a "nullable" value. A regular DateTime can't be null, but we need to accommodate nulls here.
If you're using C#6, you can do it like this, which I prefer. I didn't use it above because I don't know what version of C# you're on. Always prefer the least amount of "noise" cluttering up the code.
dateLabel = $"RWT010BP: {RWT010BP:d}";
That's the same ":d" as in String.Format("{0:d}", ...) above.
One more thing: idnum is an int, but don't ever concatenate a string value into a SQL string. That's a massive security vulnerability and people here will (rightly, I'm afraid) give you a very hard time for even contemplating it.
Use OracleCommand.Parameters instead, as shown in this answer. I would have used that even in this case, personally, just as a conditioned reflex.

"Error converting" numeric input to correct TSQL type (possible Bug)

As of now I am encountering this kind of bug
Error converting data type float to decimal.
or
Error converting data type Numeric to decimal
This is my code
using (SqlConnection reportsConn = new SqlConnection(sqlConnWriter))
{
reportsConn.Open();
SqlCommand AddReconItem = new SqlCommand();
AddReconItem.Connection = reportsConn;
AddReconItem.CommandType = CommandType.StoredProcedure;
AddReconItem.CommandText = "Updater.usp_AddReconcileItems";
// AddReconItem.Parameters.Add("#varible",SqlDbType.Decimal
AddReconItem.Parameters.AddWithValue("#ITEMWEIGHT", Math.Round(Convert.ToDouble(WeightTextBox.Text+".00"), 2));
AddReconItem.Parameters.AddWithValue("#ITEMPRINCIPALAMT", Math.Round(Convert.ToDouble(PrincipalTexAmTextBox.Text + ".00"), 2));
AddReconItem.Parameters.AddWithValue("#FORLOANMONTH", Convert.ToDateTime(YearDropDownList.SelectedValue + "/" + MonthDropDownList.SelectedValue));
AddReconItem.Parameters.AddWithValue("#STORAGEGROUPID", StorageNameDropDownList.SelectedValue);
AddReconItem.Parameters.AddWithValue("#BRANCHCODE",BranchCodeTextBox.Text);
AddReconItem.Parameters.AddWithValue("RECONID", ReconTypeDropDownList.SelectedValue);
AddReconItem.Parameters.AddWithValue("#PAWNTIX",PwnTicketTextBox.Text);
AddReconItem.Parameters.AddWithValue("#CREATEDBY", Session["UserID"].ToString());
AddReconItem.ExecuteNonQuery();
}
When I input, 123 for principalamt and itemweight it accepts the answer and treats it as a decimal, but when I input 1234 for itemweight and still 123 for Principalamt it shows that error, if I remove the conversion and change it to Convert.ToDecimal it shows Error converting data type Numeric to decimal if I use it as text it shows Error converting data type varchar to decimal
Is this a bug or something? I can't seem to find a way I tried many options but none of them have been working
My database columns are below:
I really hope you can help me understand this phenomenon
EDIT
This is the first time I saw a program accepting 123 as a valid input while 1234 is not, my database Decimal (38,6) is very large enough to accommodate this input that's why I'm looking for the answer or known bugs that can solve this problem, thank you.
I'd suggest using Decimal.TryParse instead of Convert for your principalamt value and then maybe debugging and inspecting how the value gets converted to a valid Decimal for your Money column. For example something like;
bool valid;
var dbl = Convert.ToDouble("1234.00");
valid = Double.TryParse("1234.00", out dbl);
var dcml = Convert.ToDecimal("1234.00");
valid = Decimal.TryParse("1234.00", out dcml);
I'm not sure if you should be using Double as a data type when trying to store the resultant value in a Decimal field. Double represents floating type numbers and I think you should be using the Decimal data type for your Money column as mentioned in this answer.
For ItemWeight, with a data type of decimal(38,6), you'll end up with 6 decimal places regardless of your rounding I think. Try the following in SQL Server and make sure the parameter type for #ITEMPRINCIPALAMT is DECIMAL as well (similar to my example below).
DECLARE #Var decimal(38,6) = 1234.00
DECLARE #Tbl AS TABLE
(
Test decimal(38,6)
)
INSERT INTO #Tbl (Test) Values (#Var)
SELECT * FROM #Tbl

convert a double with a comma to a variable with a point to use in sql statement

I use my double in a select statement:
code:
SqlCommand command = new SqlCommand("SELECT min(Score) FROM "+ table +" WHERE [" + sportEvent + "] < (#result);", connect);
command.Parameters.AddWithValue("#result", result);
everything works fine if double result is an integer but not if result is a comma number (example 11,34) --> it should be 11.34 to work (point instead of comma)
How can I change a double 11,34 into 11.34 ?
It appears that your code sets a string parameter as a constraint for a DB value of numeric type, letting the database do the conversion. This is not a good idea, because it takes control away from your program: should DBA decide to reconfigure your backend database to "understand" commas instead of dots, your program will stop working!
Currently, your double is in a locale-specific format. You need to parse it using the locale-specific format provider, and then set the value that you get back from the parser as the parameter of your SQL query. Assuming that the current culture is one that is using commas as decimal separator, you can do this:
command.Parameters.AddWithValue(
"#result"
, double.Parse(s, CultureInfo.CurrentCulture)
);
You can use this
result.ToString(CultureInfo.InvariantCulture)
You could try changing the variable into string:
result.ToString().Replace(',','.');
This will replace the comma with a dot.
If result is Double then:
command.Parameters.Add("#result", SqlDbType.Float).Value = result

Specified cast is not valid exception in ms access query using C#

hey guys m having this wierd exception of cast though my datatypes are correct in db:
string sql =
string.Format(
#"select aim_network_id,aim_network_name,oxinetwork_id,pack_id,pack_name,p_face_value,pm_prefix from Operator where aim_network_id='{0}'",
gridbackOffice["aim_network_id", gridbackOffice.CurrentCell.RowIndex].Value);
OleDbCommand getSelectedGridDatecmd = new OleDbCommand(sql, conn);
OleDbDataReader reader = getSelectedGridDatecmd.ExecuteReader();
while (reader.Read())
{
txtAimNetworkID.Text = reader.GetString(0);
txtAimNetworkName.Text = reader.GetString(1);
txtPARNetworkID.Text = reader.GetString(2);
txtPARFaceValue.Text = reader["p_face_value"].ToString();
//in above line if i'm doing this `reader.GetString(5)` then i'm getting specified cast exception and that to randomly i.e some time it works fine and suddenly sometime gives this exception
txtPARPackID.Text = reader.GetString(3);
txtPARPackName.Text = reader.GetString(4);
txtPARPMPrefix.Text = reader["pm_prefix"].ToString();
}
I'm little bit confused if m using this reader["p_face_value"].ToString() then my code is running very smoothly but whats the issue with using this reader.GetString(5) , according to me both method return string, nebody had faced this error b4 ?
....Error is at 4th and 7th line in while loop.
Exception:Specified cast is not valid (InvalidCastException unhandled)
According to MSDN, OleDbDataReader.GetString() does not perform any conversions before attempting to cast to a string - therefore the data retrieved must already be a string.
If there is a chance that the value in that column could be null, the docs suggest that you should check if the value is null first:
if ( !reader.IsDBNull(5) ) {
txtPARFaceValue.Text = reader.GetString(5);
}
Calling reader["p_face_value"] on a null value returns DBNull - and when you call ToString() on DBNull, you get an empty string.
From MSDN:
No conversions are performed;
therefore the data retrieved must
already be a string.
If the column is not a string type, you'll need to use the .ToString() method to convert it.
What is the datatype of p_face_value in your database?
Based on the error description given it seems that this is not a string type, so when you call:
reader.GetString(5)
the code errors out as it cannot convert whatever type it is to a string. The .ToString() method will work as this does not use a cast.
You should use GetString only when the column is a string-equivalent type in the database (like varchar), in your case "p_face_value" seems to be a numeric type, therefore it cannot simply convert it to a string.
The way you're doing it right now is the right way.

Good way to translate numeric to string, with decimal point removed?

I have to deal with a numeric value (coming from a SQL Server 2005 numeric column) which I need to convert to a string, with the caveat that the decimal point has to be removed. The data itself is accessible in C# via a DataTable/DataRow.
For example, if the SQL Server column reads 12345.678, the string should be "12345678" when all is said and done. Would it be possible to point me toward a good approach for this? Maybe there's a .Net conversion method that does this, I'm not sure.
Thanks!
There are several possible approaches. You could convert it to a string using a specific culture so that you are sure that the period is used as decimal separator, then remove the period:
string s = num.ToString(CultureInfo.InvariantCulture).Replace(".", String.Empty);
You could use a more numeric approach to multiply the valye by 10 until there are no decimals:
while (num != Math.Floor(num)) num *= 10.0;
string s = ((int)num).ToString();
what about something like
var numberWithPoint = dbGetNumber();
string numberWithOutPoint = numberWithPoint.ToString().Replace(".", string.Empty);
it's quick and dirty, but it get the job done fairly simply.
you can do it in c# like:
var myNum = 12345.678;
var myString = myNum.ToString().Replace(".","");
in sql server, you can do it like:
SELECT REPLACE( cast(myCol as varchar), '.', '') as FormattedNumber
FROM ...
What about:
// using System.Globalization;
SqlCommand cm = new SqlCommand("SELECT 12345.678 as decimal");
// ...
SqlDataReader dr = cm.ExecuteReader();
if(dr.Read())
{
string value = dr.GetValue(0).ToString()
.Replace(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "")
}
but usually when it comes from sql server, you should not convert it first to a string than to integer / double but convert it directly from object in row["column1"] to needed value, this will save you troubles handling cultures and improve performance a bit
A straightforward method is to use
string result = original.Replace(".", "")
There might be a faster method, but if this isn't in a tight inner loop, Replace should work fine.
EDIT: Fixed code example, plus:
To address culture concerns, one might use NumberFormatInfo.NumberDecimalSeparator to determine the currently defined decimal separator.
string result = Regex.Replace(original, "[^0-9]", "");

Categories

Resources