TRIM Trailing Zeros - sql

I know this is a relatively simple question, but I couldn't find anything with my keywords using Google.
I am referencing with a SQL (Oracle) to a column that has numbers like that:
100
12500
300
Now I need to remove the last 2 zeros.
This approach is not working:
Trim(TRAILING '00' FROM F0035.Nr) "Sequence",
Does anyone have any idea?
The result should be a column with numbers - not a text

See these two options:
SQL> with test (col) as
2 (select '100' from dual union all
3 select '12500' from dual union all
4 select '300' from dual
5 )
6 select col,
7 to_number(substr(col, 1, length(col) - 2)) result_1,
8 to_number(col) / 100 result_2
9 from test;
COL RESULT_1 RESULT_2
----- ---------- ----------
100 1 1
12500 125 125
300 3 3
SQL>
the first one removes the last two characters (from your sample data, it seems that they are always 00)
the second one divides that "number" by 100

You could do this:
SELECT regexp_replace(F0035.Nr, '^(.*)00$', '\1')
FROM F0035
You can easily tweak the regular expression if your requirements change subtly, such as removing more than 2 trailing zeros (e.g. ^(.*)00+), or other characters

with test (col) as (
select 10 from dual union all
select 100 from dual union all
select 1000 from dual union all
select 12500 from dual union all
select 125002 from dual union all
select 3000 from dual
)
select col,
case when substr(col, -2) = '00' then col/100 else col end newnum
from test;

If the column contains numbers, why are you using string operations?
If all values have two 00s as the end, then:
F0035.Nr / 100
If some do not, then use a case:
(case when mod(F0035.Nr, 100) = 0 then F0035.Nr / 100 else F0035.Nr end)
I don't recommend converting to a string to do numeric operations under most circumstances.

The following expression will strip off any number of zeroes from a number:
SELECT NR / POWER(10, LENGTH(REGEXP_SUBSTR(TO_CHAR(NR), '0*$')))
FROM F0035
db<>fiddle here

Related

how to get the number after '-' in Oracle

I have some strings in my table. They are like 1101-1, 1101-2, 1101-10, 1101-11 pulse, shock, abc, 1104-2, 1104-11, 2201-1, 2202-4. I tried to sort them like below:
1101-1
1101-2
1101-10
1101-11
1104-2
1104-11
2201-1
2202-4
abc
pulse
shock
But I can't get the sort correctly. Below is my codes:
select column from table
order by regexp_substr(column, '^\D*') nulls first,
to_number(substr(regexp_substr(column, '\d+'),1,4)) asc
Sort numbers as numbers:
first the ones in front of the hyphen (line #16)
then the ones after it (line #17),
then the rest (line #18)
Mind the to_number function! Without it, you'll be sorting strings! and get the wrong result.
SQL> with test (col) as
2 ( select '1101-1' from dual union all
3 select '1101-2' from dual union all
4 select '1101-10' from dual union all
5 select '1101-11' from dual union all
6 select 'pulse' from dual union all
7 select 'shock' from dual union all
8 select 'abc' from dual union all
9 select '1104-2' from dual union all
10 select '1104-11' from dual union all
11 select '2201-1' from dual union all
12 select '2202-4' from dual
13 )
14 select col
15 from test
16 order by to_number(regexp_substr(col, '^\d+')),
17 to_number(regexp_substr(col, '\d+$')),
18 col;
COL
-------
1101-1
1101-2
1101-10
1101-11
1104-2
1104-11
2201-1
2202-4
abc
pulse
shock
11 rows selected.
SQL>
For your examples, this should do:
order by regexp_substr(column, '^[^-]+'), -- everything before the hyphen
len(column),
column
To get the number after '-' specifically:
with ttt (col) as (
select cast(column_value as varchar2(10)) as second_str
from table(sys.dbms_debug_vc2coll
( '1101-1'
, '1101-2'
, '1101-10'
, '1101-11'
, '1104-2'
, '1104-11'
, '2201-1'
, '2202-4'
, 'abc'
, 'pulse'
, 'shock'
))
)
select col
, regexp_substr(col, '(^\d+-)(\d+)', 1, 1, '', 2)
from ttt;
COL SECOND_STR
---------- ----------
1101-1 1
2201-1 1
1101-10 10
1101-11 11
1104-11 11
1101-2 2
1104-2 2
2202-4 4
abc
pulse
shock
11 rows selected
This treats the text string as two values, (^\d+-) followed by (\d+), and takes the second substring (the final '2' parameter). As only positional parameters are allowed for built-in SQL functions, you also have to specify occurrence (1) and match param (null, as we don't care about case etc).

Display all the names of the employees whose names having letter A as 2nd occurrence without using like operator

For the above query, I am using regexp_count but in SQL command line I am getting regexp_count :invaild identifier;
select * from table_name WHERE (REGEXP_COUNT(column_name, 'A')) >2;
Is this query works?
I'm not sure what you really want; is it to return names whose 2nd letter is "a", or names that have two or more letters "a" within.
Anyway, pick the one you find appropriate.
SQL> create table test as
2 (select 'saritha' col from dual union all
3 select 'mamatha' from dual union all
4 select 'vaisnavi' from dual union all
5 select 'sai' from dual union all
6 select 'vijaya' from dual union all
7 select 'kumar' from dual
8 );
Table created.
2 or more letters "a":
SQL> select col
2 from test
3 where regexp_count(col, 'a') >= 2;
COL
--------
saritha
mamatha
vaisnavi
vijaya
2nd letter is "a":
SQL> select col
2 from test
3 where substr(col, 2, 1) = 'a';
COL
--------
saritha
mamatha
vaisnavi
sai
SQL>
On Oracle 10g, which doesn't support REGEXP_COUNT function, one option is to replace all letters a with an empty string (basically, you'd remove all letters a) and fetch rows whose difference of full column length and "replaced" column length is >= 2. Something like this:
SQL> select col
2 from test
3 where length(col) - length(replace(col, 'a', '')) >= 2;
COL
--------
saritha
mamatha
vaisnavi
vijaya
SQL>

How can I get a natural numeric sort order in Oracle?

I have a column with a letter followed by either numbers or letters:
ID_Col
------
S001
S1001
S090
SV911
SV800
Sfoofo
Szap
Sbart
How can I order it naturally with the numbers first (ASC) then the letters alphabetically? If it starts with S and the remaining characters are numbers, sort by the numbers. Else, sort by the letter. So SV911should be sorted at the end with the letters since it also contains a V. E.g.
ID_Col
------
S001
S090
S1001
Sbart
Sfoofo
SV800
SV911
Szap
I see this solution uses regex combined with the TO_NUMBER function, but since I also have entries with no numbers this doesn't seem to work for me. I tried the expression:
ORDER BY
TO_NUMBER(REGEXP_SUBSTR(ID_Col, '^S\d+$')),
ID_Col
/* gives ORA-01722: invalid number */
Would this help?
SQL> with test (col) as
2 (select 'S001' from dual union all
3 select 'S1001' from dual union all
4 select 'S090' from dual union all
5 select 'SV911' from dual union all
6 select 'SV800' from dual union all
7 select 'Sfoofo' from dual union all
8 select 'Szap' from dual union all
9 select 'Sbart' from dual
10 )
11 select col
12 from test
13 order by substr(col, 1, 1),
14 case when regexp_like(col, '^[[:alpha:]]\d') then to_number(regexp_substr(col, '\d+$')) end,
15 substr(col, 2);
COL
------
S001
S090
S1001
Sbart
Sfoofo
SV800
SV911
Szap
8 rows selected.
SQL>

Sort a value list that contains letters and also numbers in a specific order

I have a problem in SQL Oracle, I'm trying to create a view that contains values with letters and numbers and I want to sort them in a specific order.
Here is my query:
create or replace view table1_val (val, msg_text) as
select
val, msg_text
from
table_val
where
val in ('L1','L2','L3','L4','L5','L6','L7','L8','L9','L10','L11','L12','L13','L14','G1','G2','G3','G4')
order by lpad(val, 3);
The values are displayed like this:
G1,G2,G3,G4,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10,L11,L12,L13
The thing is that I want to display the L values first and then the G values like in the where condition. The 'val' column is VARCHAR2(3 CHAR). The msg_text column is irrelevant. Can someone help me with that? I use Oracle 12C.
You must interpret the second part of the val column as a number
order by
case when val like 'L%' then 0 else 1 end,
to_number(substr(val,2))
This work fine for your current data, but may fail in future if a new record is added with non-numeric structure.
More conservative (and more hard to write), but safe would be to used a decode for all the current keys, ordering unknown keys on the last position (id = 18 in the example):
order by
decode(
'L1',1,
'L2',2,
'L3',3,
'L4',4,
'L5',5,
'L6',6,
'L7',7,
'L8',8,
'L9',9,
'L10',10,
'L11',11,
'L12',12,
'L13',13,
'G1',14,
'G2',15,
'G3',16,
'G4',17,18)
You can't do anything based on the order of the WHERE condition
But you can use a CASE on the ORDER BY
ORDER BY CASE
WHEN SUBSTR(val, 1, 1) = 'L' THEN 1
WHEN SUBSTR(val, 1, 1) = 'G' THEN 2
ELSE 3
END,
TO_NUMBER (SUBSTR(val, 2, 10));
Another option to consider might be using regular expressions, such as
SQL> with table1_val (val) as
2 (select 'L1' from dual union all
3 select 'L26' from dual union all
4 select 'L3' from dual union all
5 select 'L21' from dual union all
6 select 'L11' from dual union all
7 select 'L4' from dual union all
8 select 'G88' from dual union all
9 select 'G10' from dual union all
10 select 'G2' from dual
11 )
12 select val
13 from table1_val
14 order by regexp_substr(val, '^[[:alpha:]]+') desc,
15 to_number(regexp_substr(val, '\d+$'));
VAL
---
L1
L3
L4
L11
L21
L26
G2
G10
G88
9 rows selected.
SQL>

Values are not displaying with leading zero in oracle

I have a table where i have data with leading zeros for a column(number datatype). When i try to query the column in apex - SQL Workshop, it is not displaying the leading zero. So i need to manually convert to display value with leading zeros. But there is a problem while converting.
If i format explicitly using to_char then it is affecting the normal value.
For example
select to_char(colA,'0.99') from tab1
will give me 0.87 when value is .87 but we do have values without decimal also. in that case it will give me ###. Basically i want to display value as it is(but add 0 if value is starting with decimal). It should not add trailing zero also.Is there any way to achieve this? For example, below will give 661.00. But it should not give. If it whole number, it should display the same value.
select to_char(661,'999G999G999G999G990D00MI') from dual
You can get close with a mask like 'FM999999990D9999', with an appropriate number of 9s each side of the decimal to cover all values you might have.
with tab1 (cola) as (
select 0.87 from dual
union select 661 from dual
union select 661.87 res from dual
union select 1.5 res from dual
)
select cola, to_char(cola, 'FM999999990D9999')
from tab1;
COLA TO_CHAR(COLA,'F
---------- ---------------
.87 0.87
1.5 1.5
661 661.
661.87 661.87
The FM removes trailing zeros and leading spaces (including a nominal space for a +/- sign).
To get rid of the trailing decimal marker too you need to trim it off:
with tab1 (cola) as (
select 0.87 from dual
union select 661 from dual
union select 661.87 res from dual
union select 1.5 res from dual
)
select cola, rtrim(to_char(cola, 'FM999999990D9999'), to_char(0, 'FMD'))
from tab1;
I've stuck with D in both parts of that; you could use a fixed . in both so you don't need the second to_char() call to convert that, but you may want it to be controlled by the session - either way it needs to be consistent.
If you don't know how many 9s you need to include, you could generate a bespoke format mask for every number, based on how many digits there are before and after the decimal separator:
with tab1 (cola) as (
select 0.87 from dual
union all select 661 from dual
union all select 661.87 res from dual
union all select 1.5 res from dual
union all select 0.00045354543 from dual
)
select cola,
'FM' || lpad('0', length(trunc(cola)), '9')
|| case when trunc(cola) != cola
then 'D' || rpad('9', length(cola - trunc(cola)) - 1, '9')
end as format_mask,
to_char(cola,
'FM' || lpad('0', length(trunc(cola)), '9')
|| case when trunc(cola) != cola
then 'D' || rpad('9', length(cola - trunc(cola)) - 1, '9')
end) as result
from tab1;
COLA FORMAT_MASK RESULT
--------------- -------------------- --------------------
.87 FM0D99 0.87
661 FM990 661
661.87 FM990D99 661.87
1.5 FM0D9 1.5
.00045354543 FM0D99999999999 0.00045354543
This relies on implicit conversion but seems to work for positive, negative and zero. It doesn't need to trim the result because the decimal separator D is only included at all for non-integers.
Think also your format mask is wrong D99 should help:
SQL> with a as
2 ( select 1/100 nb, '0.01' res from dual
3 union select 20 nb, '20' res from dual
4 union select 444/100 nb, '4.44' res from dual
5 union select 120/100 nb, '1.2' res from dual)
6 select nb, to_char(nb,'999G990D99') t_c, res from a
NB T_C RES
,01 0,01 0.01
1,2 1,20 1.2
4,44 4,44 4.44
20 20,00 20
How about using a case statement in your query for the column in question?
Something like this:
select case
when INSTR(to_char(:test_no),'.') = 1
then replace(to_char(:test_no),'.','0.')
else to_char(:test_no)
end as 'test_no'
from dual