This question already has answers here:
Oracle aggregate for joining strings with comma, and about writing custom aggregates
(3 answers)
Closed 8 years ago.
Please help me to do the following in Oracle.
I have something like column called id , and I need in concatenation
Id
1
2
3
4
5
6
8
9
9
I need a query which returns 1,2,3,4,5,6,7,8,9,9
How can I do this?
Try this,
WITH t(ID) AS
(
SELECT 1 FROM dual
UNION
SELECT 2 FROM dual
UNION
SELECT 3 FROM dual
UNION
SELECT 4 FROM dual
)
SELECT LISTAGG(ID, ',') WITHIN GROUP (ORDER BY ID)
FROM t;
try
select ltrim(max(sys_connect_by_path(id, ',')), ',')
from (select id, rownum t
from yourtable t)
connect by prior t = t - 1
start with t = 1;
Related
This question already has answers here:
How to split a varchar column as multiple values in SQL?
(2 answers)
What is alternative of Find_in_set of mysql in Oracle
(3 answers)
Oracle joining tables using WITH clause with SPLIT [duplicate]
(2 answers)
use LIKE and IN with subquery in sql [duplicate]
(4 answers)
Closed 1 year ago.
I am having 2 tables, 1 is transaction, other is trackingNumber
Transaction have trackingNumberList which contains the values like 123, 235, 55. Here 123 is the id of trackingNumber, same for other 2 values.
I wanna join transaction with trackingNumber but I haven't found any solution to join list.
I tried INSTR as well but it is not giving the correct data.
select tn.*, t.id
from transaction t
left join TrackingNumber tn on INSTR(t.trackingnumberlist, tn.id) > 0
where t.id = 2439845;
I am using ORACLE db.
Don't split the string; just wrap the list and the id in the delimiter you are using and do a sub-string match using LIKE:
select tn.*, t.id
from transaction t
left join TrackingNumber tn
on (', '||t.trackingnumberlist||', ' LIKE '%, '||tn.id||', %')
where t.id = 2439845;
If you want to use INSTR to do the same thing:
select tn.*, t.id
from transaction t
left join TrackingNumber tn
on (INSTR(', '||t.trackingnumberlist||', ', ', '||tn.id||', ') > 0)
where t.id = 2439845;
If you split comma-separated values into rows, then you can join such a subquery with another table. Have a look at the following example. Sample data in lines #1 - 11, query you might be interested in begins at line #12.
SQL> with
2 transaction (trackingnumberlist, city) as
3 (select '123, 235, 55', 'London' from dual union all
4 select '22' , 'Paris' from dual
5 ),
6 trackingnumber (id, name) as
7 (select '123', 'Little' from dual union all
8 select '235', 'Foot' from dual union all
9 select '55' , 'Sharma' from dual union all
10 select '22' , 'Barmar' from dual
11 )
12 select n.id,
13 n.name,
14 x.city
15 from trackingnumber n
16 join (select trim(regexp_substr(t.trackingnumberlist, '[^,]+', 1, column_value)) id,
17 t.city
18 from transaction t cross join
19 table(cast(multiset(select level from dual
20 connect by level <= regexp_count(t.trackingnumberlist, ',') + 1
21 ) as sys.odcinumberlist ))
22 ) x
23 on x.id = n.id
24 order by n.id, n.name;
ID NAME CITY
--- ------ ------
123 Little London
22 Barmar Paris
235 Foot London
55 Sharma London
SQL>
I wrote query
select s_id from emp
where s_inv=12
i got results in this manner
1
2
3
4
5
but i want it in this format
1 2 3 4 5
If you need your result in a single column, you can use LISTAGG:
with emp(s_id, s_inv) as
(
select 1, 12 from dual union all
select 2, 12 from dual union all
select 3, 12 from dual union all
select 4, 12 from dual union all
select 5, 12 from dual
)
select listagg(s_id, ' ') within group (order by s_id)
from emp
where s_inv = 12
If you need to build many columns on the same row, you should first define how many columns will your result have
This question already has answers here:
how to replace multiple strings together in Oracle
(5 answers)
Closed 7 years ago.
I am trying to implement a simple conversion logic to clean up data on huge oracle table using nested replace function like below ,the rules are simple for now say
LKP_TABLE
-----------
LTD ----> LIMITED
COMP ----> COMPANY
SELECT REPLACE (REPLACE ( UPPER ('This is AA LTD_COMP') ,'LTD',
'LIMITED'),'COMP','COMPANY') from dual
--output : THIS IS AN AA LIMITED_COMPANY
But in future this can be a long list and I was wondering if there is any solution other than nested replace function. TRANSLATE function can replace only specific characters only.
Note : I have restrictions in creating a custom PL/SQL functions
You can maybe try with splitting the string into words, translating each word and afterwards aggregating the string once again.
In the example below, I've assumed that the words will be separated by blankspaces and that the maximum number of words is 7 (pivot table)
with replacements as
(select 'LTD' String, 'Limited' Repl from dual
union all
select 'COMP' String, 'Company' Repl from dual
)
,MyStrings as
(select 'This is AA LTD COMP' Str, 1 strnum from dual
union all
select 'This is BB LTD COMP', 2 from dual
union all
select 'This is BB COMP', 3 from dual
)
,pivot as (
select 1 pnum from dual
union all select 2 from dual
union all select 3 from dual
union all select 4 from dual
union all select 5 from dual
union all select 6 from dual
union all select 7 from dual
)
,StrtoRow as
(
SELECT rownum rn
,ms.strnum
,REGEXP_SUBSTR (Str,'[^ ]+',1,pv.pnum) TXT
FROM MyStrings ms
,pivot pv
where REGEXP_SUBSTR (Str,'[^ ]+',1,pv.pnum) is not null
)
Select Listagg(NVL(Repl,TXT),' ') within group (order by rn)
from
(
Select sr.TXT, r.Repl, sr.strnum, sr.rn
from StrtoRow sr
,replacements r
where sr.TXT = r.String(+)
order by strnum, rn
) group by strnum
Suppose I have a table with 10 records/tuples. Now I want to update an attribute of 6th record with the same attribute of 1st record, 2nd-7th, 3rd-8th, 4th-9th, 5th-10th in a go i.e. without using cursor/loop. Use of any number of temporary table is allowed. What is the strategy to do so?
PostgreSQL (and probably other RDBMSes) let you use self-joins in UPDATE statements just as you can in SELECT statements:
UPDATE tbl
SET attr = t2.attr
FROM tbl t2
WHERE tbl.id = t2.id + 5
AND tbl.id >= 6
This would be easy with an update-with-join but Oracle doesn't do that and the closest substitute can be very tricky to get to work. Here is the easiest way. It involves a subquery to get the new value and a correlated subquery in the where clause. It looks complicated but the set subquery should be self-explanatory.
The where subquery really only has one purpose: it connects the two tables, much as the on clause would do if we could do a join. Except that the field used from the main table (the one being updated) must be a key field. As it turns out, with the self "join" being performed below, they are both the same field, but it is required.
Add to the where clause other restraining criteria, as shown.
update Tuples t1
set t1.Attr =(
select t2.Attr
from Tuples t2
where t2.Attr = t1.Attr - 5 )
where exists(
select t2.KeyVal
from Tuples t2
where t1.KeyVal = t2.KeyVal)
and t1.Attr > 5;
SqlFiddle is pulling a hissy fit right now so here the data used:
create table Tuples(
KeyVal int not null primary key,
Attr int
);
insert into Tuples
select 1, 1 from dual union all
select 2, 2 from dual union all
select 3, 3 from dual union all
select 4, 4 from dual union all
select 5, 5 from dual union all
select 6, 6 from dual union all
select 7, 7 from dual union all
select 8, 8 from dual union all
select 9, 9 from dual union all
select 10, 10 from dual;
The table starts out looking like this:
KEYVAL ATTR
------ ----
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
with this result:
KEYVAL ATTR
------ ----
1 1
2 2
3 3
4 4
5 5
6 1
7 2
8 3
9 4
10 5
Data in the file_name field of the generation table should be an assigned number, then _01, _02, or _03, etc. and then .pdf (example 82617_01.pdf).
Somewhere, the program is putting a state name and sometimes a date/time stamp, between the assigned number and the 01, 02, etc. (82617_ALABAMA_01.pdf or 19998_MAINE_07-31-2010_11-05-59_AM.pdf or 5485325_OREGON_01.pdf for example).
We would like to develop a SQL statement to find the bad file names and fix them. In theory it seems rather simple to find file names that include a varchar2 data type and remove it, but putting the statement together is beyond me.
Any help or suggestions appreciated.
Something like:
UPDATE GENERATION
SET FILE_NAME (?)
WHERE FILE_NAME (?...LIKE '%STRING%');?
You can find the problem rows like this:
select *
from Files
where length(FILE_NAME) - length(replace(FILE_NAME, '_', '')) > 1
You can fix them like this:
update Files
set FILE_NAME = SUBSTR(FILE_NAME, 1, instr(FILE_NAME, '_') -1) ||
SUBSTR(FILE_NAME, instr(FILE_NAME, '_', 1, 2))
where length(FILE_NAME) - length(replace(FILE_NAME, '_', '')) > 1
SQL Fiddle Example
You can also use Regexp_replace function:
SQL> with t1(col) as(
2 select '82617_mm_01.pdf' from dual union all
3 select '456546_khkjh_89kjh_67_01.pdf' from dual union all
4 select '19998_MAINE_07-31-2010_11-05-59_AM.pdf' from dual union all
5 select '5485325_OREGON_01.pdf' from dual
6 )
7 select col
8 , regexp_replace(col, '^([0-9]+)_(.*)_(\d{2}\.pdf)$', '\1_\3') res
9 from t1;
COL RES
-------------------------------------- -----------------------------------------
82617_mm_01.pdf 82617_01.pdf
456546_khkjh_89kjh_67_01.pdf 456546_01.pdf
19998_MAINE_07-31-2010_11-05-59_AM.pdf 19998_MAINE_07-31-2010_11-05-59_AM.pdf
5485325_OREGON_01.pdf 5485325_01.pdf
To display good or bad data regexp_like function will come in handy:
SQL> with t1(col) as(
2 select '826170_01.pdf' from dual union all
3 select '456546_01.pdf' from dual union all
4 select '19998_MAINE_07-31-2010_11-05-59_AM.pdf' from dual union all
5 select '5485325_OREGON_01.pdf' from dual
6 )
7 select col bad_data
8 from t1
9 where not regexp_like(col, '^[0-9]+_\d{2}\.pdf$');
BAD_DATA
--------------------------------------
19998_MAINE_07-31-2010_11-05-59_AM.pdf
5485325_OREGON_01.pdf
SQL> with t1(col) as(
2 select '826170_01.pdf' from dual union all
3 select '456546_01.pdf' from dual union all
4 select '19998_MAINE_07-31-2010_11-05-59_AM.pdf' from dual union all
5 select '5485325_OREGON_01.pdf' from dual
6 )
7 select col good_data
8 from t1
9 where regexp_like(col, '^[0-9]+_\d{2}\.pdf$');
GOOD_DATA
--------------------------------------
826170_01.pdf
456546_01.pdf
To that end your update statement might look like this:
update your_table
set col = regexp_replace(col, '^([0-9]+)_(.*)_(\d{2}\.pdf)$', '\1_\3');
--where clause if needed