How would you specify this:
Decimal(18,2)
In this:
SqlComm.Parameters.Add("#myValue", SqlDbType.Decimal, 0, "myValue");
Currently I have defined precision = 2 from the design side properties. I'm just curious as to how to accomplish this from the code. Thanks
There's not an overload of Add that lets you set the decimal precision inline, so you either need to create a SQlParameter object and add it to the collection:
SqlParameter param = new SqlParameter("#myValue", SqlDbType.Decimal);
param.SourceColumn = "myValue";
param.Precision = 18;
param.Scale = 2;
SqlComm.Parameters.Add(param);
or keep a reference to the parameter after adding it:
SqlParameter param = SqlComm.Parameters.Add("#myValue", SqlDbType.Decimal, 0, "myValue");
param.Precision = 18;
param.Scale = 2;
or using the parameter constructor:
SqlComm.Parameters.Add(new SqlParameter(
parameterName = "#myValue",
dbType = SqlDbType.Decimal,
precision = 18,
scale = 2,
sourceColumn = "myValue"));
var cmd = new SqlCommand()
SetDecimalParameter(cmd.Parameters.Add("#paramName", SqlDbType.Decimal), 18, 2).Value = 12.34;
SqlParameter SetDecimalParameter(SqlParameter parameter, byte precision, byte scale) {
parameter.Precision = precision;
parameter.Scale = scale;
return parameter;
}
My answer is not directly connected with the OP's question, but I've seen a lot of people asking "why set the precision since it is taken from the value".
It has to do with the way SQL Server works when comparing the decimal parameter with the text column. Imagine you have column named strNumberColumn witch is of nvarchar type. If you define a #var Decimal(1,0) = '1', comparison on the condition where strNumberColumn >= #var will work only as long, as the longest entry in that column is between "0" and "9". If any of the entries go beyond, for example "10" or "123" you will get an OverflowException while converting string to decimal. What is important, that conversion is made "behind the scenes".
Please, do not bring arguments like "if that column should contain numbers it should not be made nvarchar" - I totally agree, but that is beyond the scope of the problem (sometimes you work with a legacy system and you have no influence over the column datatype). The above example shows a real life scenario when defining precision is required in order for the query to run successfully despite having a smaller precision amount assigned to the variable (like #var Decimal(12,2) = '1.0').
Related
I am reading about Enums and came across an example where the writer showed how we can typecast an enum to int and an int to an enum. However I didnt get how can we change the value of an enumeration by creating a reference of type TrickScore.
public enum TrickScore {
Sit = 7,
Beg = 25,
RollOver = 50,
Fetch = 10,
ComeHere = 5,
Speak = 30,
}
This code block changes the value of Fetch enumeration. I am unable to understand how score gets set to TrickScore.Fetch. When I call score.ToString(), it returns Fetch.
int value = (int)TrickScore.Fetch * 3;
MessageBox.Show(value.ToString());
TrickScore score = (TrickScore)value;
MessageBox.Show(score.ToString());
I'm afraid your understanding of enums is not quite right. This line of code:
int value = (int)TrickScore.Fetch * 3;
doesn't change value of TrickScore.Fetch. It takes the value of TrickScore.Fetch (10) multiplies it by 3 and assigns it to a variable value. In this case you are using TrickScore.Fetch almost as if it were a variable that keeps a number. When you have something like y = x * 5 you don't change a value of x. Only assigning the result to y.
Next line in your code that does something is this one:
TrickScore score = (TrickScore)value;
So you have your variable value (30) from previous operation. You cast the value to TrickScore enum type. The item with this number is Speak and it is assigned to the score variable.
One thing worth noting is that only because enum inherits from int doesn't mean it's a good practice to perform arithmetic operations on enums. I'd avoid casting them on ints and performing mathematical operations. After all does it really make sense to add up TrickScore.Beg and TrickScore.ComeHere and expect it to result in TrickScore.Speak?
I have code that is taking information from the database to insert into a list. One piece of data that I'm taking will be used for price. (I set its type to decimal in SQL Server), for example: " 1,80".
But when I select it, my decimal variable returns the value 2 !
I want to know if there are a simple way to make decimal not automatically round numbers.
This is the code:
public decimal preco { get; set; }
while (dr.Read())
{
clsCaProd oProd = new clsCaProd();
oProd.cod = dr.GetInt32(0);
oProd.preco = dr.GetDecimal(1); // Here returns "2" instead of "1,80"
oProd.info = dr.GetString(2);
oProd.categ = dr.GetString(3);
oProd.nome = dr.GetString(4);
lProd.Add(oProd);
}
If you declare a column as decimal, the default "scale" is zero. You need to specify the precision and scale.
Try this example:
declare #d1 decimal = 1.80
declare #d2 decimal(19,4) = 1.80
select #d1, #d2;
Results:
2 1.8000
am using a Prepared Statement in C#.
SqlCommand inscommand = new SqlCommand(supInsert, connection);
inscommand.Parameters.Add("#ordQty", SqlDbType.Decimal,18);
inscommand.Prepare();
u = inscommand.ExecuteNonQuery();
The above code throws below Exception:
SqlCommand.Prepare method requires parameters of type 'Decimal' have an explicitly set Precision and Scale.
EDIT: How to avoid this Exception
The following would set a Decimal with Precision 18 and Scale 8 (Decimal (18,8))
SqlCommand insertCommand= new SqlCommand(supInsert, connection);
insertCommand.Parameters.Add("#ordQty", SqlDbType.Decimal,18);
insertCommand.Parameters["#ordQty"].Precision = 18;
insertCommand.Parameters["#ordQty"].Scale = 8;
insertCommand.Prepare();
u = insertCommand.ExecuteNonQuery();
As the exception pointed out, you have to explicitly set the SqlParameter.Precision and SqlParameter.Scale properties in order to use the decimal type as a parameter.
Let's say your SQL field is of type decimal(18,8). The way to do this inline is to use brace-initialization for your SqlParameter while adding it to the SqlParameterCollection, as follows:
cmd.Parameters.Add(new SqlParameter("#ordGty", SqlDbType.Decimal) {
Precision = 18, Scale = 8 });
You can also do
cmd.Parameters.Add(new SqlParameter("#ordGty", SqlDbType.Decimal) {
Precision = 18, Scale = 8}).Value = 0.4m; // or whatever
to add the value, if you need one. You could even do
cmd.Parameters.Add(new SqlParameter("#ordGty", SqlDbType.Decimal) {
Precision = 18, Scale = 8, Value = 0.4m /* or whatever */});
if you prefer. Brace initialization is really powerful.
Side note: I realize that this is an old question, but I think this form is much more readable than creating the object while adding it to the list and then setting the scale and precision. For Posterity! (since this is a high-listing google search result)
try this:
SqlParameter parameter = new SqlParameter("#ordQty", SqlDbType.Decimal);
parameter.Precision = 18;
parameter.Scale = 0;
parameter.Value = YOURVALUEHERE;
inscommand.Parameters.Add(parameter);
You will have to explicitly define precision and scale for this parameter.
SqlParameter ordQty = cmd.Parameters.Add("#ordQty", SqlDbType.Decimal);
ordQty.Precision = x; //Replace x with what you expect in Sql Sp
ordQty.Scale = y; //Replace y with what you expect in Sql Sp
ordQty.Value = 18; //Set value here
inscommand.Parameters.Add(ordQty);
When I add a value to my SqlDataRecord some how it is round the value. I am not sure what is causing it.
EDIT: John made a good point Left out the property type for dm which is "decimal?"
TotalCount = 2.5245332200983
SqlDataRecord rec = new SqlDataRecord(
new SqlMetaData("TotalCount", SqlDbType.Decimal));
rec.SetNullableDecimal(0,dm.TotalCount);
When it is written to the DB it is showing 3.0000000000000
Database Type added so I can pass a TVP:
CREATE TYPE dbo.TestCount AS TABLE(
TotalCounts decimal(38,20) NULL
);
Database Table:
CREATE TABLE dbo.TestCountTbl(
TotalCounts decimal(38,20) NULL);
What am I doing wrong? Is the SqlDbType wrong?
EDIT: Per #user957902 I had to add precision / scale to my SqlDataRecord....totally makes sense...duh. So I added that and works like a charm. Thanks All!
SqlDataRecord rec = new SqlDataRecord(
new SqlMetaData("TotalCount", SqlDbType.Decimal,38,20));
According to the documentation for the SqlMetaData constructor you are using here, for SqlDbType.Decimal, the default for Precision is 18 and for scale is 0. So by default its not going to store anything past the decimal. You will need to use the constructor that allows you to set precision and scale descibed here.
public SqlMetaData(
string name,
SqlDbType dbType,
byte precision,
byte scale
)
i have a table in my database as freespace... it has a column called freesize with its datatype as int.
i have three valuse in it :
1065189988
1073741818
1073741819
now i try to get the total free space but i get an error.
private void GetFreeSpace()
{
DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection();
connection.ConnectionString = ConfigurationManager.ConnectionStrings["SumooHAgentDBConnectionString"].ConnectionString;
connection.Open();
SqlCommand sqlCmd = new SqlCommand("select sum(freesize)* 0.000000000931322575 as freespace from freespace", connection);
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCmd);
sqlDa.Fill(dt);
connection.Close();
if (dt.Rows.Count > 0)
{
double freeSpace = Convert.ToDouble(dt.Rows[0]["freespace"].ToString());
}
}
Arithmetic overflow error converting expression to data type int.
Line 123: SqlCommand sqlCmd = new SqlCommand("select sum(freesize)* 0.000000000931322575 as freespace from freespace", connection);
Line 124: SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCmd);
Line 125: **sqlDa.Fill(dt);** here i get error
Line 126: connection.Close();
Line 127: if (dt.Rows.Count > 0)
Any suggestions of how to get the value in freespace without changing the datatype?
Thanks
I know it works good with bigint, but I want int.
So you're summing 3 large integers, then multiplying by a tiny double, but still want the output to be an int?
you could retrieve each row as an int, then do your math in c#
or you could cast the int to a bigint or double before the sum, so you don't overflow there.
You've got two choices as far as I can tell: use Li0liQ's approach, something on the order of
SELECT SUM(freesize * 0.000000931322575) ...
which may suck because of accuracy concerns; or, sucking it up and using a bigint. That raises the question: why are you so concerned with using an int rather than a bigint? If all you have is a hammer, then go nuts. But I'd at least consider using bigint if there isn't a compelling reason not to.
The sum of the 3 values alone are larger than the data type size for an Int in SQL which is defined as the range:
-2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647)
As such you could do the following:
select cast(sum(cast(freesize as bigint))* 0.000000000931322575 as int) as freespace from freespace
Which will support the math and get you back the result as an INT but this cast will just truncate the value and return 2 while as a double it would be 2.99 so you would also want to have SQL round the number appropriately.
Multiply by C < 1, and then sum.
Multiply first, then SUM?
select cast(sum(freesize* 0.000000000931322575) as int)...
However, as Adam Gritt pointed out, do you want 2 or 3 as your answer: round or truncate? So, expanding on is answer... To round correctly as deal with truncation, add 0.5 before the cast back to int
select cast(sum(freesize* 0.000000000931322575) + 0.5 as int)...