Related
In the Oracle database, I have string values (VARCHAR2) like 1,4,7,8. The number represents as 1=car, 2= bus, 3=BB, 4=SB, 5=Ba, 6=PA, 7=HB, and 8 =G
and want to convert the above-said example to "car,SB,HB,G" in my query results
I tried to use "Decode" but it does not work. Please advise how to make it works. Would appreciate.
Thanks`
Initially, I have used the following query:
Select Clientid as C#, vehicletypeExclusions as vehicle from
clients
The sample of outcomes are:
C# Vehicle
20 1,19,20,23,24,7,5
22 1,19,20,23,24,7,5
I also tried the following that gives me the null value of vehicles:
Select Clientid as C#, Decode (VEHICLETYPEEXCLUSIONS, '1', 'car',
'3','bus', '5','ba' ,'7','HB', '8','G'
, '9','LED1102', '10','LED1104', '13','LED8-2',
'14','Flip4-12', '17','StAT1003', '19','Taxi-Min', '20','Tax_Sed',
'21','Sup-veh' , '22','T-DATS', '23','T-Mini',
'24','T-WAM') as vehicle_Ex from clients >
Here's one option. Read comments within code. Sample data in lines #1 - 13; query begins at line #14.
SQL> with
2 expl (id, name) as
3 (select 1, 'car' from dual union all
4 select 2, 'bus' from dual union all
5 select 3, 'BB' from dual union all
6 select 4, 'SB' from dual union all
7 select 5, 'Ba' from dual union all
8 select 6, 'PA' from dual union all
9 select 7, 'HB' from dual union all
10 select 8, 'G' from dual
11 ),
12 temp (col) as
13 (select '1,4,7,8' from dual),
14 -- split COL to rows
15 spl as
16 (select regexp_substr(col, '[^,]+', 1, level) val,
17 level lvl
18 from temp
19 connect by level <= regexp_count(col, ',') + 1
20 )
21 -- join SPL with EXPL; aggregate the result
22 select listagg(e.name, ',') within group (order by s.lvl) result
23 from expl e join spl s on s.val = e.id;
RESULT
--------------------------------------------------------------------------------
car,SB,HB,G
SQL>
Using the function f_subst from https://stackoverflow.com/a/68537479/429100 :
create or replace
function f_subst(str varchar2, template varchar2, subst sys.odcivarchar2list) return varchar2
as
res varchar2(32767):=str;
begin
for i in 1..subst.count loop
res:=replace(res, replace(template,'%d',i), subst(i));
end loop;
return res;
end;
/
I've replaced ora_name_list_t (nested table) with sys.odcivarchar2list (varray) to make this example easier, but I would suggest to create your own collection for example create type varchar2_table as table of varchar2(4000);
Example:
select
f_subst(
'1,4,7,8'
,'%d'
,sys.odcivarchar2list('car','bus','BB','SB','Ba','PA','HB','G')
) s
from dual;
S
----------------------------------------
car,SB,HB,G
Assume you have a lookup table (associating the numeric codes with descriptions) and a table of input strings, which I called sample_inputs in my tests, as shown below:
create table lookup (code, descr) as
select 1, 'car' from dual union all
select 2, 'bus' from dual union all
select 3, 'BB' from dual union all
select 4, 'SB' from dual union all
select 5, 'Ba' from dual union all
select 6, 'PA' from dual union all
select 7, 'HB' from dual union all
select 8, 'G' from dual
;
create table sample_inputs (str) as
select '1,4,7,8' from dual union all
select null from dual union all
select '3' from dual union all
select '5,5,5' from dual union all
select '6,2,8' from dual
;
One strategy for solving your problem is to split the input - slightly modified to make it a JSON array, so that we can use json_table to split it - then join to the lookup table and re-aggregate.
select s.str, l.descr_list
from sample_inputs s cross join lateral
( select listagg(descr, ',') within group (order by ord) as descr_list
from json_table( '[' || str || ']', '$[*]'
columns code number path '$', ord for ordinality)
join lookup l using (code)
) l
;
STR DESCR_LIST
------- ------------------------------
1,4,7,8 car,SB,HB,G
3 BB
5,5,5 Ba,Ba,Ba
6,2,8 PA,bus,G
I need an Oracle function to check if the given input string is valid.
For eg. input string is 50-100,145,153
The function should check
num1 < num2 in num1-num2
the string pattern should always be num1-num2,num3,num4
Thanks
There's no built-in function, but you can use regular expressions. For example (only the first row is valid):
SQL> with test (col) as
2 (select '50-100,145,153' from dual union all
3 select '50-49,145,153' from dual union all
4 select 'a-2,b,200' from dual union all
5 select '10-20,30' from dual union all
6 select '1,2-3,4' from dual
7 )
8 select col
9 from test
10 where regexp_like(col, '^\d+-\d+,\d+,\d+$')
11 and to_number(regexp_substr(col, '\w+', 1, 1)) < to_number(regexp_substr(col, '\w+', 1, 2));
COL
--------------
50-100,145,153
SQL>
I would use this approach:
with test (col) as
(select '50-100,145,153' from dual union all -- ok
select '50-49,145,153' from dual union all
select 'a-2,b,200' from dual union all
select '10-20,30' from dual union all -- ok
select '1,2-3,4' from dual union all -- ok
-- additional test values:
select '1,2,3,7-8,100,120-130,200' from dual union all -- ok
select '1-3,7-8,120-130,200' from dual union all -- ok
select '1,2,3,8-7,100,120-130,200' from dual union all -- nope
select '1,2,3,7-8,100,130-120,200' from dual union all -- nope
select '1,2,3,7-8,100,,,120-z,200' from dual union all -- nope
select '1,2,3,7-8,100,,,120,200' from dual -- nope
)
select col
from test
where regexp_like(col, '^(((\d+-\d+)|\d+),?)+$')
and (select
count(*)
from dual
where to_number(regexp_substr(col,'(\d+)-(\d+)',1,level,null,1))
> to_number(regexp_substr(col,'(\d+)-(\d+)',1,level,null,2))
connect by level<=regexp_count(col,'(\d+)-(\d+)')
) = 0;
regexp_like(col, '^(((\d+-\d+)|\d+),?)+$') checks that col consist only from 2 patterns: \d+-\d+ and \d+ with comma between them.
in the subquery we check if there is num1>num2
I have following source data in VARCHAR2 format
,00100000004749745
,100000001490116
,125
,200000002980232
,25
,439999997615814
,5
0
1
1,10000002384186
1,5
100
2,1800000667572
3
3,29999995231628
96
999
What is the formula to transfer it to NUMBER?
With the following
INSERT INTO table_b.column_b
SELECT
TO_NUMBER (column_a,'9999999999D9999999999999999999999',
'nls_numeric_characters= ''.,''') as my_numbers
FROM table_a.column_a;
I get an error
ORA-01722: invalid number error message.
I assume that it is because rows starting with comma e.g (,125).
In destination table I need in number format the data like this
0,00100000004749745
0,100000001490116
0,125
0,200000002980232
0,25
0,439999997615814
0,5
0
1
...
Also tried to put zero '0' in front of comma and them change it to number with
Select
column_a,
TO_NUMBER (column_a,'9999D9999999999999999999999',
'nls_numeric_characters= ''.,''') as my_number
from
(SELECT DISTINCT
'0'|| column_a
FROM table_a.column_a
WHERE column_a LIKE (',125')
);
but the result was
0,125 125
As Vasyl stated, your nls_numeric_characters needs to be adjusted. The query below demonstrates how to convert the string to a number.
WITH
my_numbers (column_a)
AS
(SELECT ',00100000004749745' FROM DUAL
UNION ALL
SELECT ',100000001490116' FROM DUAL
UNION ALL
SELECT ',125' FROM DUAL
UNION ALL
SELECT ',200000002980232' FROM DUAL
UNION ALL
SELECT ',25' FROM DUAL
UNION ALL
SELECT ',439999997615814' FROM DUAL
UNION ALL
SELECT ',5' FROM DUAL
UNION ALL
SELECT '0' FROM DUAL
UNION ALL
SELECT '1' FROM DUAL
UNION ALL
SELECT '1,10000002384186' FROM DUAL
UNION ALL
SELECT '1,5' FROM DUAL
UNION ALL
SELECT '100' FROM DUAL
UNION ALL
SELECT '2,1800000667572' FROM DUAL
UNION ALL
SELECT '3' FROM DUAL
UNION ALL
SELECT '3,29999995231628' FROM DUAL
UNION ALL
SELECT '96' FROM DUAL
UNION ALL
SELECT '999' FROM DUAL)
SELECT n.column_a,
TO_NUMBER (n.column_a,
'9999999999D9999999999999999999999999999',
'nls_numeric_characters= '', ''') AS column_a_as_number
FROM my_numbers n;
Looks like you use wrong nls_numeric_characters values. Try to replace 'nls_numeric_characters=''.,''' with 'nls_numeric_characters='', '''
Explanation: Your nls_numeric_characters defined . as a decimal delimiter and , as a group delimiter, but, according to your example, you assume that the decimal delimiter is ,
I have a table new_table
ID DESCRIPTION
1 abdad jadjnd kandkadn 01/19-P-154-37
2 jscbsjc jscnscj 01/19-H-443-38 sbjcj sjcnjscn
3 scjbcs sc, scnsc 01/19-P-16-39 sjcbnjcs
4 scbcsjc 01/19-K-139-40 hcbchsb
AND LISTS
01/19-P-154-37
01/19-H-443-38
01/19-K-139-40
I want to
select * from new_table where descriptin in (
01/19-P-154-37
01/19-H-443-38
01/19-P-16-39
01/19-K-139-40
)
OR LIKE I don't now please help
I guess you want something like this (join with like operator):
with new_table (ID, DESCRIPTION) as (
select 1 ,'abdad jadjnd kandkadn 01/19-P-154-37' from dual union all
select 2 ,'jscbsjc jscnscj 01/19-H-443-38 sbjcj sjcnjscn' from dual union all
select 3 ,'scjbcs sc, scnsc 01/19-P-16-39 sjcbnjcs' from dual union all
select 4 ,'scbcsjc 01/19-K-139-40 hcbchsb' from dual
) ,
LISTS(val) as(
select '01/19-P-154-37' from dual union all
select '01/19-H-443-38' from dual union all
select '01/19-K-139-40' from dual
)
-- Below is actual query:
select new_table.* from new_table
inner join LISTS
on new_table.DESCRIPTION like '%'||LISTS.val||'%'
My Input pattern like:
WITH data_tab AS (
SELECT '1540_INPUTTER' user_name FROM dual
UNION SELECT '1540_RAZZ25_UNKNOWN' FROM dual
UNION SELECT '1540_RAKIB17_OS_WIN10' FROM dual
)
SELECT REGEXP_SUBSTR(user_name,…………………….....) AS st_user_name from data_tab
Desired Output:
ST_USER_NAME
------------
INPUTTER
RAZZ25
RAKIB17
One way to do that is
WITH data_tab AS (
SELECT '1540_INPUTTER' user_name FROM dual
UNION SELECT '1540_RAZZ25_UNKNOWN' FROM dual
UNION SELECT '1540_RAKIB17_OS_WIN10' FROM dual
)
SELECT REGEXP_SUBSTR(user_name,'_([^_]*)', 1, 1, 'i', 1) AS st_user_name
FROM data_tab;
Another way to do it is to define the complete structure of the string
and extract the second group:
WITH data_tab AS (
SELECT '1540_INPUTTER' user_name FROM dual
UNION SELECT '1540_RAZZ25_UNKNOWN' FROM dual
UNION SELECT '1540_RAKIB17_OS_WIN10' FROM dual
)
SELECT REGEXP_SUBSTR(user_name,'(\d{4}_)([A-Z0-9]+)(_)?(\w+)?',1,1,'i',2)
AS st_user_name
FROM data_tab;
Check This.
WITH data_tab AS (
SELECT '1540_INPUTTER' user_name FROM dual
UNION SELECT '1540_RAZZ25_UNKNOWN' FROM dual
UNION SELECT '1540_RAKIB17_OS_WIN10' FROM dual
)
SELECT
case when INSTR(SUBSTR(user_name, INSTR(user_name, '_')+1, length(user_name)- INSTR(user_name, '_')+1 ),'_') =0 then
SUBSTR(user_name, INSTR(user_name, '_')+1, length(user_name)- INSTR(user_name, '_')+1 )
else
substr((SUBSTR(user_name, INSTR(user_name, '_')+1, length(user_name)- INSTR(user_name, '_')+1 )), 1, INSTR(SUBSTR(user_name, INSTR(user_name, '_')+1, length(user_name)- INSTR(user_name, '_')+1 ),'_') -1)
end as user_name
from data_tab