What does 'XXXXXX' mean as the second argument to TO_NUMBER? Oracle SQL - oracle

CREATE OR REPLACE TRIGGER fund_BIU
BEFORE INSERT OR UPDATE ON fund
FOR EACH ROW
BEGIN
IF INSERTING AND :new.fundid IS NULL THEN
:new.fundid := TO_NUMBER(SYS_GUID(), 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
END IF;
END;
/
I'm interested the IF statement. What does it mean
:new.fundid := to_number(sys_guid(),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');. To be precise sys_guid(), 'xxxxxxxx' part.
TY

Think of the number 33. Focus on what that means - it's a number, it does not have digits. It can be represented as 3 * 10 + 3 * 1 which is why it has two digits in base 10, both digits equal to 3. But you could also represent it as 33.00. The strings '33' and '33.00' are clearly different (one has two characters, the other has five); but if you want to think of them as representing numbers, they represent the same number - the integer 33. Similarly, +33 and +33.00 represent the same number.
If you input a string like '33' or '+33.00' but you want to get out a number, then you use the function TO_NUMBER(). For example: '+33.00' is a string, but TO_NUMBER('+33.00') is a number, the number 33.
TO_NUMBER() allows you to give a format model, so that Oracle understands how to interpret the string it receives as input.
For example, if you input the string '1101' - is that the number one thousand one hundred one, or is it the number 13, given in binary representation?
Similarly, the number 33 has the string representation '21' in hexadecimal ("in HEX"). TO_NUMBER('21') will output the number 21; but you can tell Oracle that you meant a hexadecimal number, by providing the format model 'XX'. There are two X for two digits, and X is often used to mean "hex". So TO_NUMBER('21', 'XX') will output the number 33, not the number 21.
SYS_GUID() outputs the hexadecimal representation of a very large number. The output is a string. Applying TO_NUMBER() to it, with a format model that indicates it should be interpreted as a hex number, will convert it to an actual number (instead of a string of hex digits).

What SYS_GUID() does is generate a unique 16 byte identifier or key. When applying the TO_NUMBER() function, you are getting the 32 number representation of that key. It is basically a way of generating unique numbers in Oracle.
See SYS_GUID() in Oracle documentation: https://docs.oracle.com/cd/B12037_01/server.101/b10759/functions153.htm

Related

Format mask with leading zero for NUMBER

Which format mask should I use to convert number data from table column NUMBER to char if I want to preserve one leading zero and don't know data "size"? Value could have integral and/or fractional part. All that I know - it's NUMBER.
Source Data (numbers)
.12345678901234567890
100
100.500
12345678901234567890.1234567890
Desired result (text)
0.1234567890123456789
100
100.5
12345678901234567890.123456789
and so on, i.e. number could have unpredictable number of digits in whole part and unpredictable number of digits in fractional part.
A NUMBER data type is a binary value that has no format; if you want to format the number then you will need to convert it to another data-type that can represent the numeric value with a format, such as a VARCHAR2 data-type using the TO_CHAR function:
SELECT value,
RTRIM(
TO_CHAR( value, 'FM999999999999999999999990D99999999999999999999' ),
'.'
) AS formatted_number
FROM table_name
Which, for the sample data:
CREATE TABLE table_name ( value ) AS
SELECT .12345678901234567890 FROM DUAL UNION ALL
SELECT 100 FROM DUAL UNION ALL
SELECT 100.500 FROM DUAL UNION ALL
SELECT 12345678901234567890.1234567890 FROM DUAL
Outputs:
VALUE
FORMATTED_NUMBER
.1234567890123456789
0.1234567890123456789
100
100
100.5
100.5
12345678901234567890.123456789
12345678901234567890.123456789
number could have unpredictable number of digits in whole part and unpredictable number of digits in fractional part.
Just increase the number of 9s before and after the D decimal separator until the number of integer/fractional digits reaches your maximum precision.

Cast bigint to decimal(18,5) in hive

I'm trying to cast a bigint to decimal(18,5) in hive and I'm not getting any fraction values after converting to decimal(18,5).
Let's take the below bigint values
99000
999000
499000
350000
344000000
After casting to decimal(18,5), I'm expecting something like below
0.99000
9.99000
4.99000
3.50000
3440.00000
I'm trying the below query.
select col_a, cast(col_a as decimal(18,5)) from table;
From above query, I'm getting output same as input
99000
999000
499000
350000
344000000
Also, I tried dividing the input with 10^5 and casting to decimal(18,5).
select col_a, cast(col_a/100000 as decimal(18,5)) from table;
Above query is returning the fraction values, but not having 5 digits after the decimal.
0.99
9.99
4.99
3.5
344000000
Could someone please correct me what I'm missing or doing wrong here.
DECIMAL type do not permit values larger than the range implied by the column definition.
DECIMAL(5,0) column supports a range of -99999 to 99999.
DECIMAL(M,D) column permits up to M - D digits to the left of the decimal point.
For example DECIMAL(5,2) permits -999.99 to 999.99
And the trailing zeroes are not displayed. If you need them guaranteed to be displayed, use string type and rpad() function to add zeroes at the end or something like that.
If the number cannot be cast to decimal, NULL is returned, for example the following cast returns NULL:
select cast(1234567890L as decimal(3,1))
It is not clear why do you expect cast a bigint to decimal(18,5) to produce some fractional numbers. cast does not divide your initial numbers.

Oracle 12c - how much does it really affect Varchar column comparing to Number column? [duplicate]

Let's say I have a table in Oracle 12c with columns:
create table t1 (
a number (5,0),
b varchar (5,0)
d ...
e ...
);
Then I insert 100,000,000 records in both columns which have the same values - e.g.
20151 and '20152' ... (for a first record)
20152 and '20152' ... (for a second record)
20153 and '20153' ... (for a third record)
...
Then I add index 1 on column 'a' and index 2 on column 'b'.
Question is - would the query perform equally fast when executing against column 'a' as on column 'b' (e.g. join query with other table based on a column 'a' or based on a column 'b' or WHERE clause on either of columns)?
Also - would using index on a 'varchar' column - use more CPU than using index on a 'number' column?
Thanks.
[TL;DR] Use dates to store dates, numbers to store numbers and strings to store strings.
How about resource usage?
Oracle stores the NUMBER data type as 1 byte per 2 digits.
Oracle stores the CHAR data type as 1 byte per ASCII character (UTF-8 and other encodings may take more for characters in extended sets) and will right-pad the string with space characters so the strings are all exactly the same length.
Oracle stores the VARCHAR2 data type as 1 byte per ASCII character plus a small overhead (1 or 2 bytes) for the string length.
Oracle stores the DATE data type as 7 bytes (2 for year and 1 for each of month, day, hour, minute, second).
Based on your previous question you appear to be storing year and quarter and assuming that you are always going to have 4-digit years and 1-digit quarters then:
NUMBER(5,0) would take 3 bytes;
CHAR(5 CHARACTER) would take 5 bytes;
VARCHAR2(5 CHARACTER) would take 6 bytes; and
DATE would take 7 bytes.
So only considering memory a NUMBER(5,0) would be the most efficient.
However
As soon as you start to do arithmetic on year/quarters stored as numbers/strings then you get into performance issues:
For example, getting the next quarter :
If quarter is a NUMBER data type then you could use: CASE WHEN MOD(quarter,10) = 4 THEN quarter + 7 ELSE quarter + 1 END but this doesn't handle when you want to add 5 quarters or start subtracting quarters and then the logic starts to get much more complicated.
If quarter is a CHAR data type then you could convert it to a number or a date and use either of those methods (string manipulation is not likely to be performant).
If quarter is a DATE then you just need to use ADD_MONTHS( quarter, 3 ).
The DATE method is self-documenting and already exists whereas the NUMBER method would just become a custom function for your approximation of a QUARTER data type and once you implement all the comparison and manipulation functions you need you will have effectively rewritten the DATE data type as a UDT for quarters and those functions will be less perfomant than the optimised date functions.
Don't use inappropriate data types - just store dates as dates; numbers as numbers; and strings as string.

Decimal precision in hive

I want to add the decimal precision to be set for the values
Example:
select 1*1.00000;
output: 1.0
Even tried with cast
select cast(cast(1*1.0000 as double) as decimal(5,2))
output: 1
I want the results to be displayed as 1.000. Is there any way to do so in hive?
Create a table and test it. It works if we give the exact precision value as mentioned in the decimal function.
create table test1_decimal (b decimal (5,3));
INSERT INTO test1_Decimal values(1.000); //This will shrink it to 1 as the total digits is not five.
INSERT INTO test1_Decimal values(123.12345); //This results in NULL as it exceeds the total digits(5).
INSERT INTO test1_Decimal values(12.123); //This will give you exact result as the precision and number of digits fits. Ouputs as 12.123
So if the value matches the decimal function then it displays correctly else it shrinks or converts to NULL.

Decimal place require in Oracle

case 1: SELECT TO_CHAR(12345.6789, '99999D99') FROM dual;
Output: 12345.67
case 2: SELECT TO_CHAR(12345.6789, '999D99') FROM dual;
Output: ######
case 3: SELECT TO_CHAR(12345, '99999D99') FROM dual;
Output: 12345.00
case 4: SELECT TO_CHAR(12345.1, '99999D99') FROM dual;
Output: 12345.10
Here Problem is if we don't know how many digits before decimal then how to manage for correct answer.[only case 1,3,4 can resolved using by TO_CHAR but how to solve for case 2.]
In this case the simplest answer might be to not supply a format model at all, but truncate or round the value to two decimal places:
SELECT TO_CHAR(ROUND(12345.6789, 2)) as rounded,
TO_CHAR(TRUNC(12345.6789, 2)) as truncated
FROM dual;
ROUNDED TRUNCATED
-------- ---------
12345.68 12345.67
From the documentation:
If you omit fmt, then n is converted to a VARCHAR2 value exactly long enough to hold its significant digits.
Otherwise you'd need to supply a format model that allowed for the maximum size of your number; if it's unrestricted you'd need 36 nines, the decimal separator, and two more nines. The result would be padded with spaces so you might also want to trim it, depending on how you'll use the string value.
SELECT TO_CHAR(12345.6789, '999999999999999999999999999999999999D99') as val
FROM dual;
VAL
----------------------------------------
12345.68
You could also do that flexibly by using the length of the truncated value (i.e. once the decimal places have been removed):
SELECT TO_CHAR(12345.6789,
lpad('9', length(trunc(12345.6789)), '9') || 'D99') as val
FROM dual;
VAL
---------
12345.68
But that seems unnecessarily complicated when you can let Oracle work it out for you.
However, if you want the decimals to show trailing zeros then you might need to use that method; but with zeros after the decimal separator:
SELECT TO_CHAR(12345.6, lpad('0', length(trunc(12345.6)), '9') || 'D00') as val
FROM dual;
VAL
---------
12345.60
... which addresses the 3rd and 4th cases you added. I've made it show a leading zero for values less than 1 as well; the generated format model in this case is '99990D00'. The number of nines will still vary depending on the size of your number.
By default Oracle still leaves a space at the start for a potential minus sign. You can avoid that with the FM format modifier:
SELECT TO_CHAR(12345.6, 'FM'
|| lpad('0', length(trunc(12345.6)), '9') || 'D00') as val
FROM dual;
VAL
--------
12345.60
You could always go with the maximum number of digits you expect to be present in the input. If there are fewer digits in the input than your format specifier, it wouldn't affect the outcome in anyway. For instance,
select to_char(12323.5553,'99999D99') from dual
would produce,
123.56
As you said, the length of the input is unknwon. So why would you use a fixed length formater for somthing that is unknown? Does not work. Read your input as String from the beginning and manipulate it as String or even better - BLOB.
Well, to do the rounding correct might be tricky.
So, best check your data if the numbers will realy get so big, because that would mean a lot of work and trouble.
If not more than 38 Digits are needed, you can go with decimal or numeric datatype and (if you insist on a formatter) use the TM formatter for example.
SELECT to_char(cast(1234.456 as decimal( *,2)), 'TM') as a FROM dual
or take the advice that was given above by the other posters.

Resources