Removing a trailing period from improperly joined Teradata column - sql

I have a Teradata table that I've inherited that was not formatted in a great manner.
ID
123456789.
234567890.
I've tried:
TRIM(new_card_srgt_id (FORMAT 'Z(17)9'))
but my version of Teradata gave a funny error:
Format string has combination of numeric, character, and GRAPHIC values.
Any suggestions welcomed.
UPDATE: The suggestion to use TRIM(trailing '.' from ID) results in a numeric overflow when I went to cast it. Any other way to fix it.

When you load data from a decimal field into a character field without specifying the format, teradata does the type conversion. It inherently adds '.' to the trailing value.
If the ID field is char and it already contains '.' and you want to extract it as decimal without the '.' then the syntax is as follows
SELECT cast(id as decimal(15,0)) form table;
If the ID field is decimal and you want to extract it as character without the '.' then the syntax is as follows
SELECT TRIM(ID (FORMAT 'ZZZZZZZZZZZZZ9')) from table;

Solved it with:
cast(TRIM(trailing '.' from ID) as decimal(18,0))

Related

Conversion of decimal separator - DB2 SQL

I want to convert a double value column in DB2 SQL with ',' comma decimal separator to '.' dot decimal separator. My local settings are German. I can't change the DB settings since many applications are involved.
Eg : column value =0,81234 I want it to be displayed as 0.81234.
SELECT CAST(CAST(COLUMNNAME AS DECIMAL(8,2)) AS VARCHAR(25))
I tried converting it to decimal(8,2) first and then to varchar. This results in 0.81 (with '.' as expected). But I need all the numbers right of the decimal separator like 0.81234. So, I tried with decimal(7,6) which results in SQL0413N OVERFLOW OCCURRED DURING NUMBER DATA TYPE CONVERSION error.
Is there any other way to display the decimal separator as '.'?
The separator is not actually stored in the DB for numeric columns.
Configure whatever tool you are using to look at the data to use your separator of choice.
Optionally you can run
set option decmpt = *PERIOD;
before running your select.
if you use JDBC you can modify it by adjusting your Connection string. Just add this
:decimalSeparator=1;
for point as decimal separator or 2 for comma as decimal separator

Oracle SQL replace

Unfortunately I don't have the possibility to change field type.
I would like to REPLACE a , to . in a Typ=1 type of field (e.g.: 4,37 so in the end it should be 4.37), and I've tried CAST() and TO_NUMBER and TO_CHAR and I don't even know what else also, but I keep getting the ORA-01722 and it drives me crazy already. Why does it have to be a number for replacing ???
SELECT REPLACE(fmm, ',', '.') fmm FROM ...
Or do you have a better idea how can I do it without REPLACE maybe ?
UPDATE: it seems he has a problem with:
ORDER BY TO_NUMBER(fmm, '99D99')
So it seems he is taking the replaced version, so with . of fmm, but why ????
Try to remove the commas by replace(nvl(nr,0),',',''), and then formatting by
with tab as
(
select '1,234,567' as nr
from dual
)
select to_char(
replace(nvl(nr,0),',','')
,'fm999G999G990','NLS_NUMERIC_CHARACTERS = '',.''')
as "Number"
from tab;
Number
----------
1.234.567
Demo
Passing a string (varchar2) value into the replace function cannot throw an ORA-01722.
it seems he has a problem with:
ORDER BY TO_NUMBER(fmm, '99D99')
If that's complaining when fnm is '4,37' then you could add a replace() call inside the to_number(), but it's simpler/clearer to specify the NLS_NUMERIC_CHARACTERS as part of the conversion, so it knows that D is represented by a comma, and doesn't rely on the session settings:
order by to_number(fnm, '99D99', 'NLS_NUMERIC_CHARACTERS=,.')
If your table has a mix of values with period and comma decimal separators then you need to fix the data - this is the main reason you should not be storing numbers as strings in the first place. If you can't fix the data then you can workaround it with replace(), but it isn't ideal; you can then use a fixed period as the decimal character:
order by to_number(replace(fnm, ',', '.'), '99.99');
or still specify NLS_NUMERIC_CHARACTERS:
order by to_number(replace(fnm, ',', '.'), '99D99', 'NLS_NUMERIC_CHARACTERS=.,')
Either way that is 'normalising' all the string to only have periods, with no commas; and that allows them all to be converted.
db<>fiddle
what I don't understand, if I do some changes in the SELECT to a field, how can it affect the ORDER BY section? fmm should still remain 4,37 and not 4.37 in the ORDER BY section, shouldn't it?
No, because you gave the column expression REPLACE(fmm, ',', '.') the alias fnm, which is the same as the original column name; and the order-by clause is the only place column aliases are allowed, where it masks the original table column. When you do:
ORDER BY TO_NUMBER(fmm, '99D99')
the fnm in that conversion is the value of the column expression aliased as fnm, and not the original table column.
You can still access the table column, but to do so you have to prefix it with table name or alias, as the column from expression from the select list takes precedence (which is implied but not stated clearly in the docs:
expr orders rows based on their value for expr. The expression is based on columns in the select list or columns in the tables, views, or materialized views in the FROM clause.
So you can either explicitly refer to the table column via the table name or, here, an alias:
SELECT REPLACE(t.fmm, ',', '.') fmm
FROM your_table t
ORDER BY TO_NUMBER(t.fmm, '99D99')
though you still shouldn't rely on the session NLS settings really, so can/should still specify the NLS option to match the table column format:
SELECT REPLACE(t.fmm, ',', '.') fmm
FROM your_table t
ORDER BY TO_NUMBER(t.fmm, '99D99', 'NLS_NUMERIC_CHARACTERS=,.')
or use the replaced value and specify the NLS option for that (notice the option itself is different):
SELECT REPLACE(fmm, ',', '.') fmm
FROM your_table
ORDER BY TO_NUMBER(fmm, '99D99', 'NLS_NUMERIC_CHARACTERS=.,')
db<>fiddle
If your table has a mix of period and comma values then you need to use the column-alias version so it is consistent when it tries to convert. If you you only have commas then you can use either. (But again, you shouldn't be storing numbers as strings in the first place...)

In db2 how to select a column in integer having aligned it to right with leading spaces?

I need to extract a report from some tables using db2 having pgm(dnatiaul).
Using a query i want to get the below output with first char to be spaces.
ex: integer(16)
54457750
49457750
o/p: char(int(16))
54457750
49457750
As i am trying to convert it to char it is aligning to left.
I tried Lpad which gives me **extra length i.e (18) + '.' also
Help me
LPAD is the right choice, but you would need to specify how long the result string needs to be. This can be done using CAST. Here I cast the result to 10 characters.
db2 "select cast(lpad(123422,10,' ') as char(10)) as testme from sysibm.sysdummy1"
TESTME
----------
123422
1 record(s) selected.
DIGITS(integer_column_name) will give you a character string of CHAR(10) with the numeric value right-justified and left-filled with zeroes. Thus, an integer column containing 543210 will become a character string containing 0000543210.
Likewise, DIGITS(small_integer_column_name) will give you a character string of CHAR(5)

Can't cut and convert a string - weird format

This question is almost the same with one of my previous questions, which can be found HERE
I have a field named: pa_value which keeps varchar records
Now this field contains records like:
0,5582
0,6985
-0,1589
0,9856
-0,6589
I'm getting these results using the following code:
CAST (replace (p7.pa_value ,'%','') AS float (3,0)) as TotalMargin
What I'm trying to do is to remove everything and leave just 5 characters(or 6 if there is a -(minus) infront of the string).
It should be looking like this:
55.82
69.85
-15.89
98.56
-65.89
I tried to cast it as a float and then to convert it to integer. I also tried the floor command, which is not for my case, without any success. I'm always getting a syntax error message. I believe that there is no way to do this
SELECT p7.pa_value=CASE WHEN LEFT( p7.pa_value,1)='-' THEN '-' +
CONVERT(varchar(max),CONVERT(float,substring(p7.pa_value,4,4))/100) ELSE
CONVERT(varchar(max),CONVERT(float,substring(p7.pa_value,3,4))/100) END
FROM <table_name>
What is being done ..
Check if starting character is '-'.
If yes then extract string starting from position 4 else starting
from position 3.
The inner convert function converts string to float for division and
the outer convert changes back the resultant value back to varchar
type.
If you know there are always four digits after the comma, you could use this, though I don't believe it's perfect:
CONVERT(NUMERIC(9,2), REPLACE(REPLACE(p7.pa_value, '%', ''), ',', '')) / 100

How do you convert from scientific notation in Oracle SQL?

We are trying to load a file created by FastExport into an oracle database.
However the Float column is being exported like this: 1.47654345670000000000 E010.
How do you configure SQL*Loader to import it like that.
Expecting Control Script to look like:
OPTIONS(DIRECT=TRUE, ROWS=20000, BINDSIZE=8388608, READSIZE=8388608)
UNRECOVERABLE LOAD DATA
infile 'data/SOME_FILE.csv'
append
INTO TABLE SOME_TABLE
fields terminated by ','
OPTIONALLY ENCLOSED BY '"' AND '"'
trailing nullcols (
FLOAT_VALUE CHAR(38) "???????????????????",
FILED02 CHAR(5) "TRIM(:FILED02)",
FILED03 TIMESTAMP "YYYY-MM-DD HH24:MI:SS.FF6",
FILED04 CHAR(38)
)
I tried to_number('1.47654345670000000000 E010', '9.99999999999999999999 EEEE')
Error: ORA-01481: invalid number format model error.
I tried to_number('1.47654345670000000000 E010', '9.99999999999999999999EEEE')
Error: ORA-01722: invalid number
These are the solutions I came up with in order of preference:
to_number(replace('1.47654345670000000000 E010', ' ', ''))
to_number(TRANSLATE('1.47654345670000000000 E010', '1 ', '1'))
I would like to know if there are any better performing solutions.
As far as I'm aware there is no way to have to_number ignore the space, and nothing you can do in SQL*Loader to prepare it. If you can't remove it by pre-processing the file, which you've suggested isn't an option, then you'll have to use a string function at some point. I wouldn't expect it to add a huge amount of processing, above what to_number will do anyway, but I'd always try it and see rather than assuming anything - avoiding the string functions sounds a little like premature optimisation. Anyway, the simplest is possibly replace:
select to_number(replace('1.47654345670000000000 E010',' ',''),
'9.99999999999999999999EEEE') from dual;
or just for display purposes:
column num format 99999999999
select to_number(replace('1.47654345670000000000 E010',' ',''),
'9.99999999999999999999EEEE') as num from dual
NUM
------------
14765434567
You could define your own function to simplify the control file slightly, but not sure it'd be worth it.
Two other options come to mind. (a) Load into a temporary table as a varchar, and then populate the real table using the to_number(replace()); but I doubt that will be any improvement in performance and might be substantially worse. Or (b) if you're running 11g, load into a varchar column in the real table, and make your number column a virtual column that applies the functions.
Actually, a third option... don't use SQLLoader at all, but use the CSV file as an external table, and populate your real table from that. You'll still have to do the to_number(replace()) but you might see a difference in performance over doing it in SQLLoader. The difference could be that it's worse, of course, but might be worth trying.
Change number width with "set numw"
select num from blabla >
result >> 1,0293E+15
set numw 20;
select num from blabla >
result >> 1029301200000021
Here is the solution I went with:
OPTIONS(DIRECT=TRUE, ROWS=20000, BINDSIZE=8388608, READSIZE=8388608)
UNRECOVERABLE LOAD DATA
infile 'data/SOME_FILE.csv'
append
INTO TABLE SOME_TABLE
fields terminated by ','
OPTIONALLY ENCLOSED BY '"' AND '"'
trailing nullcols (
FLOAT_VALUE CHAR(38) "REPLACE(:FLOAT_VALUE,' ','')",
FILED02 CHAR(5) "TRIM(:FILED02)",
FILED03 TIMESTAMP "YYYY-MM-DD HH24:MI:SS.FF6",
FILED04 CHAR(38)
)
In my solution the conversion to a number is implicit:
"REPLACE(:FLOAT_VALUE,' ','')"
In Oracle 11g, it's not needed to convert numbers specially.
Just use integer external in the .ctl-file:
I tried the following in my Oracle DB:
field MYNUMBER has type NUMBER.
Inside .ctl-file I used the following definition:
MYNUMBER integer external
In the datafile the value is: MYNUMBER: -1.61290E-03
As for the result: sqlldr loaded the notation correctly: MYNUMBER field: -0.00161290
I am not sure if it's a bug or a feature; but it works in Oracle 11g.