How to cast char without decimal point to decimal in Teradata? - sql

I've got a field where data is stored as char(9). The content is numeric and actually a decimal value. Unfornutately the stored value itself doesn't contain a decimal point, only numbers.
I want to store this value inside a decimal(9,2) field. I know that I could use string functions to add a decimal point at the right position, but I'm wondering if there is a nicer way to do this cast. Maybe with TO_NUMBER and the right format string?
Example:
CHAR(9): '000123456' -> DECIMAL(9,2): 1234.56

If you want to avoid string functions, it might be easier to cast to decimal then divide by 100

Related

Truncation using round function isn't achieved as expected in sql server

I have a field stored in float datatype. I need to convert it to numeric without it getting implicitly rounded in the process of conversion.
I have tried round(float_data,scale,1). Seems to work fine for most of the cases.but when the number of digits after decimal places is less than scale mentioned in round function it tries to floor down the number rather than appending 0 at the end.
For instance, round (0.0243,5,1) returns 0.02429. Why isn't it simply truncating the number to the number of digits mentioned?
I know this issue is when we use float as source datatype but I cannot change the source datatype.
The same truncation happens right when the same is achieved via ssis. Is there any way in sql to achieve this?
Because when converted to a float, the decimal 0.0243 is stored as 0.02429999969899654388427734375, which truncates to 0.02429. Looks like you want to round instead of truncate, eg
declare #f float = 0.0243
select round(#f,5,0)

How can I convert a hex number to integer in SQL, when the resulting value is larger than bigint?

I have a hex number in string form, for example, 0x47423f34b640c3eb6e2a18a559322d68. When I try to convert this to an int, for comparison with another value that is an int, I run up against the BIGINT size limit. I've tried various methods such as decimal, etc, but dont seem to be able to get past the 64bit size limit.
Ideally, I'd like a conversion that converts from a hex string, to an int string, so I can bypass the int limits. However, doing this without using intermediate conversions (to values that are out of range) is causing me some problems.
An alternative solution would be to be able to convert from a decimal string (the other comparison value, which in the example given, is 94719161261466374640962917648041127272), to hex, or to binary, for comparison. I already have a routine that can convert arbitrary length hex strings to binary without overflowing intermediate variables, but I haven't had much luck doing decimal strings to binary without using intermediate variables, so I can't currently compare them that way either.
I already have a c# based solution for this conversion, so I could use SQL CLR or other similar solutions, but I'd much prefer a native SQL method for doing this conversion (decimal string to hex string or binary string, or hex string to decimal string or binary string).
The SQL Server 2008 release updated the See CONVERT() here function to be able to convert hexadecimal values:
select convert(bigint, convert (varbinary(8), '0x0000010d1858798c', 1))
Result:
1155754654092 (decimal) ( == 0x0000010d1858798c )

SQL ROUND() function with truncate takes 119.1 and returns 119.09

I have data for pounds and pence stored within concatenated strings (unfortunately no way around this) but can not guarantee 2 decimal places.
E.g. I may get a value of 119.109, so this must translated to 2 decimal places with truncation, i.e. 119.10, NOT 119.11.
For this reason I am avoiding "CAST as Decimal" because I do not want to round. Instead I am using ROUND(amount, 2, 1) to force truncation at 2 decimal places.
This works for the most part but sometimes exhibits strange behaviour. For example, 119.10 outputs as 119.09. This can be replicated as:
ROUND(CAST('119.10' AS varchar),2,1)
My target field is Decimal(19,4) (but the 3rd and 4th decimal places will always be 0, it is a finance system so always pounds and pence...).
I assume the problem is something to do with ROUNDing a varchar....but I don't know anyway around this without having to CAST and therefore introduce rounding that way?
What is happening here?
Any ideas greatly appreciated.
This is due to the way floating point numbers work, and the fact that your string number is implicitly converted to a floating point number before being rounded. In your test case:
ROUND(CAST('119.10' AS varchar),2,1)
You are implicitly converting 119.10 to float so that it can be passed to the ROUND function, 119.10 exactly cannot be stored as a float, proven by running the following:
SELECT CAST(CONVERT(FLOAT, '119.10') AS DECIMAL(30, 20))
Which returns:
119.09999999999999000000
Therefore, when you round this with truncate you get 119.09.
For what it is worth, you should always specify a length when converting to, or declaring a varchar

is there a numeric type in SQL with a maximum length?

I'm using PostgreSQL and I need an attribute type that can store a numeric value that can't have more than 7 digits.
Is there an attribute like that or do I need to make it a text column that can only store numbers?
DECIMAL and NUMERIC (synonyms for each other) will provide this functionality. You specify total digits, and digits to the right of the decimal point. For example NUMERIC(9,7) for ##.#######.
Often, when you have a "numeric" value that is fixed in digits, then you really have something like an account number. Although this looks like a number, it really, it really isn't for a few reasons:
Leading zeros are important
You can't perform arithmetic on the value
Sometimes, individual digits might have a particular meaning
If this is what you are trying to do, I would suggest that you use CHAR(7) and explicitly include leading zeroes. If you really do have a number with these constraints, you can use DECIMAL(7). If you do use CHAR(7), you can use a check constraint to validate the digits.

how can I preserve the digits following the decimal place in a money datatype?

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)