We have SQL Server 2000 database with money data type columns and we have strange problem with numbers within money columns in which we store numbers with 2 decimal places. For o long time everything was OK. But now I see that in some rows where was number 47.22 is now number 47.2178. When i select CAST(COLUMN as CHAR) result is 47.22 but when i retrieve value from ADO recordset i have result 47.2178. I browse all application if there is any place where it can write number with 4 decimal places and find nothing(and in application history log there are records that application writes 47.22 to database). Can it be some SQL Server problem?
edit:application is written in VB6
Are you actually using the money data type or are you using a floating point type?
What happens when you use enterprise manager to select from that table? Does everything look ok?
My guess is that you are converting the data to a floating point type somewhere along the way. Probably in the ADO code.
UPDATE
Per MS: When casting money to a string type, the machine's locale comes into play. Which is why it is rounded to 2 decimal places.
You have three options.
First cast the money type to an equivalent decimal then cast that result to a char
Change the machines Regional Settings to default to the format you want.
Don't use the money data type to begin with, just use a decimal.
Don't use Enterprise Manager to draw any conclusions on what is really stored in your tables. EM has sometimes its own opinion on how to interpret data.
Looking at your CAST(....to CHAR) the reason is explained in the documentation (look for CAST & CONVERT)...
The following table shows the values
for style that can be used for
converting money or smallmoney to
character data.
Value Output
0 (default) No commas
every three digits to the left of the
decimal point, and two digits to the
right of the decimal point; for
example, 4235.98.
1 Commas every
three digits to the left of the
decimal point, and two digits to the
right of the decimal point; for
example, 3,510.92.
2 No commas
every three digits to the left of the
decimal point, and four digits to the
right of the decimal point; for
example, 4235.9819.
EDIT: Finally figured out how to use the BlockQuote feature. :-)
Related
I have a table ProductAmount with columns
Id [BIGINT]
Amount [FLOAT]
now when I pass value from my form to table it gets stored in format 2.46237846387469E+15 whereas actual value was 2462378463874687. Any ideas why this value is being converted and how to stop this?
It is not being converted. That is what the floating point representation is. What you are seeing is the scientific/exponential format.
I am guessing that you don't want to store the data that way. You can alter the column to use a fixed format representation:
alter table ProductAmount alter amount decimal(20, 0);
This assumes that you do not want any decimal places. You can read more about decimal formats in the documentation.
I would strongly discourage you from using float unless:
You have a real floating point number (say an expected value from a statistical calculation).
You have a wide range of values (say, 0.00000001 to 1,000,000,000,000,000).
You only need a fixed number of digits of precision over a wide range of magnitudes.
Floating point numbers are generally not needed for general-purpose and business applications.
The value gets stored in a binary format, because this is what you specified by requesting FLOAT as the data type for the column.
The value that you store in the field is represented exactly, because 64-bit FLOAT uses 52 bits to represent the mantissa*. Even though you see 2.46237846387469E+15 when selecting the value back, it's only the presentation that is slightly off: the actual value stored in the database matches the data that you inserted.
But i want to store 2462378463874687 as a value in my db
You are already doing it. This is the exact value stored in the field. You just cannot see it, because querying tool of SQL Management Studio formats it using scientific notation. When you do any computations on the value, or read it back into a double field in your program, you will get back 2462378463874687.
If you would like to see the exact number in your select query in SQL Management Studio, use CONVERT:
CONVERT (VARCHAR(50), float_field, 128) -- See note below
Note 1: 128 is a deprecated format. It will work with SQL Server-2008, which is one of the tags of your question, but in versions of SQL Server 2016 and above you need to use 3 instead.
Note 2: Since the name of the column is Amount, good chances are that you are looking for a different data type. Look into decimal data types, which provide a much better fit for representing monetary amounts.
* 2462378463874687 is right on the border for exact representation, because it uses all 52 bits of mantissa.
I have a float type column in my database table . When i parse the 10 digit value as float from front end and store in the table. It gets stored in E raise to power form
Whereas if i manually enter a 10 digit value in SQL database nothing like that happens
What should i do?
The data is also getting rounded off for example i an entering 5666666666
and this is what happens
better use DECIMAL(12,2) for this kind of field.
Decimal and Numeric (T-SQL)
It seems your front end only accepts 7 digits in the mantissa and the database accepts 15. You might achieve what you want by increasing precision in the front end data type.
That being said, please try to get your client to use an exact (decimal) type for this column instead.
Check front end app weather it does rounds up floater and tell your client to use money for a data type.
Alternative to float use numeric or decimal with precision (you will make shure it is a precision u want to keep).
Due to floater is a number calculated with a base of 2, you can have a gaps like one you presented in saving data. That why u NEVER use float for money data.
how can I preserve the digits following the decimal place in a money datatype?
the problem I have is every time I try to cast the data to a string, I lose precision...
for example:
I am trying to use a money datatype to store phone numbers (it seems like the most optimal storage size) EDIT: storage size is a major issue for me (8 bytes for money datatype instead of 16+ bytes for varchar field)
If I am storing 10 digits on the right side of the decimal place and 3-4 digits on the right of the decimal place as the extension, when I try to 'parse' the extension, I seem to lose anything more than 2 digits
so a phone number like this: (305) 444-1234 ext 283 would be stored in a money datatype like this: 3054441234.283
the problem I have is if I use a CAST(myMoneyValue as varchar(x)) then 3054441234.283 turns into 3054441234.28
can anyone help?
EDIT2: let's pretend for a moment I didn't mention storing a phone number in there... let's say there was a reason I needed to concatenate a money datatype together with a varchar field... e.g. If I wanted to concatenate '$' + 0.1125 + ' / sqft.' - is there any way to preserve the .0025 portion of the money field?
You store phone numbers in varchar fields, perhaps decomposed into country/area codes, extension number etc.
If you insist, then either:
use STR to format the value
use CONVERT(varchar(20), MyMoneyColumn, 2)
What about the leading zeroes used in many countries?
Stop using the money datatype to store phone numbers. If you want it as a varchar then store it as a varchar. It doesn't make sense to store this as something else just to convert it later on.
It will also confuse others that look at your data later on (say after you are hit by a bus and leave no documentation behind). Also, casting can cause problems with index usage and can really slow down your queries.
CAST(myMoneyValue as varchar(x)) assumes two decimal places by default (converting money to varchar). You can force it to whatever number of decimal places you want.
BUT YOU CANNOT KNOW if it's a 3 or 4 digit extension in advance (1234567.123 - is that 123-4567 x 123 or 123-4567 x 1230 - they are both the same in money/decimal's internal representations - unless you go to the trouble of always padding them on the left after the decimal - 1234567.0123 is 123-4567 x 123 - so now the money aren't even as human readable in their "native form").
I think this pretty much shows why you shouldn't use decimal or money for this data.
You are trying really hard to complicate your task - simply store the phone number as char or varchar of appropriate length.
Regarding EDIT2:
The style value for money or smallmoney conversion to character data is:
0 (default) - no commas every three digits to the left of the decimal point, and two digits to the right of the decimal point; for example, 4235.98
1 - commas every three digits to the left of the decimal point, and two digits to the right of the decimal point; for example, 3,510.92
2 - no commas every three digits to the left of the decimal point, and four digits to the right of the decimal point; for example, 4235.9819
You need to use the last one:
CONVERT(varchar(x), myMoneyValue, 2)
Your biggest problem is that you're trying to store a phone number in a money datatype. Don't do that, and then you won't have this problem.
A phone number is not a "number" in the traditional sense. Leading zeros are significant, for instance.
try casting as NUMERIC(14,4). Money is not a good data type for this, for precisely the reasons you are seeing.
Runnable example
-- http://msdn.microsoft.com/en-us/library/ms187928.aspx
DECLARE #money AS MONEY = 12345.6789
SELECT CONVERT(varchar, #money), CONVERT(varchar, #money, 2)
I have a MySQL table with column of type float(10, 6).
If I insert 30.064742 into the column the value stored in the database is 30.064741.
Why?
Floating-point numbers imply a certain amount of imprecision. Use a DECIMAL column if you need to be certain to retain every digit.
It's a general problem with rounding numbers to a precision which can be stored in the database. Floats will round to multiples of powers of two. If you want something that is easier to think about, you can use the Decimal type, which will round to powers of ten.
More details in the documentation for numeric types:
When such a column is assigned a value with more digits following the decimal point than are allowed by the specified scale, the value is converted to that scale. (The precise behavior is operating system-specific, but generally the effect is truncation to the allowable number of digits.)
This is on Microsoft SQL Server. We have a query where we are trying to join two tables on fields containing numeric data.
One table has the field defined as numeric(18,2) and the other table has the field defined as decimal(24,4). When joining with the native data types, the query hangs and we run out of patience before it will finish (left it running 6 min…). So we tried casting the two fields to be both numeric(18,2) and the query finished in under 10 seconds. So we tried casting the two fields to be both decimal(18,2) and again the query hangs. Does anyone know the difference between the decimal and numeric data types that would make them perform so differently?
DECIMAL and NUMERIC datatypes are the one and the same thing in SQL Server.
Quote from BOL:
Numeric data types that have fixed
precision and scale.
decimal[ (p[ ,s] )] and numeric[ (p[
,s] )] Fixed precision and scale
numbers. When maximum precision is
used, valid values are from - 10^38 +1
through 10^38 - 1. The ISO synonyms
for decimal are dec and dec(p, s).
numeric is functionally equivalent to
decimal.
From that, I'm surprised to hear of a difference. I'd expect the execution plans to be the same between the 2 routes, can you check?
Why are you using two datatypes to begin with? If they contain the same type of data (and joining on them implies they do), they should be the same datatype. Fix this and all your problems go away. Why waste server resources continually casting to match two fields that should be defined the same?
You of course may need to adjust the input variables for any insert or update queries to match waht you chose as the datatype.
My guess is that it's not a matter of a specific difference between the two data types, but simply the fact that SQL Server needs to implicitly convert them to match for the join operation.
I don't know why there would be a difference from your first query and the second, where you explicitly convert, but I can see why there might be a problem when you convert to a datatype that doesn't match and then SQL Server has to implicitly convert them anyway (as in your third case). Maybe in the first case, SQL Server is implicitly converting both to decimal(24,4) so as not to lose data and that operation takes longer than converting the other way. Have you tried explicitly converting the numeric(18,2) to a decimal(24,4)?