Skip to Main Content
  • Questions
  • Comma separated string value to show it as List (one single Column)

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Pranav.

Asked: February 03, 2016 - 11:43 am UTC

Last updated: February 04, 2016 - 9:45 am UTC

Version: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

Viewed 10K+ times! This question is

You Asked

Hi,
i have Comma separated string value in column of table make_item.
i wanted to show it as List (one single Column). Below is Create and Insert table statement to make it easier. Desire result is also shown.

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

CREATE TABLE MAKE_ITEM
(
ITEM_ID NUMBER,
STYLE_TAGS NVARCHAR2(300),
STYLE_TAGS_O NVARCHAR2(300)
)
/
Insert into MAKE_ITEM
(ITEM_ID,
STYLE_TAGS, STYLE_TAGS_O,
)
Values
(100001,'Full-Sleeve,Half-Sleeve,Pocket,Cuff,Cut,Cross,Slim Fit,Normal Fit,Loose Fit,Fit Knock,Button Design,Button Digit',
'Full-Sleeve,Half-Sleeve,Pocket,Cuff,Cut,Cross,Slim Fit,Normal Fit,Loose Fit,Fit Knock,Button Design,Button Digit'
);
/
Insert into MAKE_ITEM
(ITEM_ID,
STYLE_TAGS, STYLE_TAGS_O,
)
Values
(100002,'Full-Sleeve,Half-Sleeve,Pocket,Cuff,Cut,Cross,Slim Fit,Normal Fit,Loose Fit,Fit Knock,Button Design,Button Digit',
'Full-Sleeve,Half-Sleeve,Pocket,Cuff,Cut,Cross,Slim Fit,Normal Fit,Loose Fit,Fit Knock,Button Design,Button Digit'
);
COMMIT;
/

Result : (not yet done)
Full-Sleeve
Half-Sleeve
Pocket
Cuff
Cut
Cross
Slim Fit
Normal Fit
Loose Fit
Fit Knock
Button Design
Button Digit

/

My Query :

select
level,
item_id,
regexp_substr(style_tags, '[^,]+', 1, (ROW_NUMBER() OVER(PARTITION BY item_id ORDER BY 1))) result1
-- regexp_substr(style_tags_o, '[^,]+', 1, (ROW_NUMBER() OVER(PARTITION BY item_id ORDER BY 1))) result2
--ROW_NUMBER() OVER(PARTITION BY item_id ORDER BY 1),
--(length(regexp_replace(style_tags, '[^,]+')) + 1) cnt
from make_item -- where
where style_tags is not null
--and item_id = 100001
connect by level <= length(regexp_replace(style_tags, '[^,]+')) + 1

Links i have followed :
1) https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4359323800346522748
2) http://psoug.org/reference/connectby.html
3) http://steve-lyon.blogspot.in/2013/07/aggregated-lists-decomposing-and.html
4) http://tkyte.blogspot.in/2007/03/stringing-them-up.html
5) https://docs.oracle.com/cd/B12037_01/server.101/b10759/functions116.htm

and Chris said...

Thanks for a complete test case and showing your working!

Items 100001 and 100002 appear the same though - is this intentional?

There are various ways you can do this. Your approach is close, it's just inefficient. Here's another:

- Generate a row for each item you want to display
- Join this generated table back to the table (cartesian product)
- Use the rownums from the generated table to do the substring

with rws as (
  select rownum r from dual
  connect by level <= (
    select max(regexp_count(style_tags, ',')) from make_item
  )
)
  select regexp_substr(style_tags, '[^,]+', 1, rws.r) results
  from   make_item, rws
  where  item_id = 100001;

RESULTS                                                                                                                                                        
--------------
Full-Sleeve                                                                                                                                                     
Half-Sleeve                                                                                                                                                     
Pocket                                                                                                                                                          
Cuff                                                                                                                                                            
Cut                                                                                                                                                             
Cross                                                                                                                                                           
Slim Fit                                                                                                                                                        
Normal Fit                                                                                                                                                      
Loose Fit                                                                                                                                                       
Fit Knock                                                                                                                                                       
Button Design                                                                                                                                                   

 11 rows selected

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Regexp ?

Rajeshwaran, Jeyabal, February 03, 2016 - 3:22 pm UTC

A solution without Regexp

Darryl Grubbs, February 03, 2016 - 11:35 pm UTC

Here is a possible solution without using regexp:

SELECT element_no 
       , Substr(list_string, startpos, Instr(list_string, ',', startpos) - startpos) separated_element 
  FROM ( -- Find Starting position in original string of each element
         SELECT list_string 
               , element_no 
               , nbr_of_elements 
               , Instr(list_string, ',', 1, element_no) + 1 startpos 
          FROM ( -- Create rows equal to # of elements
                 SELECT list_string  -- 
                       , LEVEL element_no 
                       , nbr_of_elements 
                  FROM ( -- Find # of elements in string
                         SELECT list_string 
                               , Length(list_string) - Length(Replace(list_string, ',', '')) - 1 nbr_of_elements 
                          FROM ( -- Place Beginning and Ending comma
                                 SELECT ','  
                                       || style_tags 
                                       || ',' list_string 
                                  FROM make_item 
                                 WHERE item_id = 100001)) 
                CONNECT BY LEVEL <= nbr_of_elements));  

Connor McDonald
February 04, 2016 - 2:37 am UTC

Thanks for the contribution

with MODEL / Table un-nesting / 12c (cross apply)

Rajeshwaran, Jeyabal, February 04, 2016 - 7:07 am UTC

rajesh@ORA10G> column txt format a20
rajesh@ORA10G> select item_id, nvl(b2,b1) txt
  2  from make_item
  3  model
  4    partition by (item_id)
  5    dimension by (1 x)
  6    measures( cast(null as nvarchar2(2000)) b1 ,
  7              cast(null as nvarchar2(2000)) b2 ,
  8              style_tags )
  9    rules iterate(100) until( b2[iteration_number] is null)
 10    ( b1[iteration_number] = case when cv(x) = 0 then style_tags[1]
 11                                  else substr( b1[cv()-1] ,instr( b1[cv()-1],',')+1) end ,
 12      b2[iteration_number] =substr( b1[cv()] , 1, instr(b1[cv()],',')-1 ) )
 13  /

   ITEM_ID TXT
---------- --------------------
    100001 Half-Sleeve
    100001 Full-Sleeve
    100001 Pocket
    100001 Cuff
    100001 Cut
    100001 Cross
    100001 Slim Fit
    100001 Normal Fit
    100001 Loose Fit
    100001 Fit Knock
    100001 Button Design
    100001 Button Digit
    100002 Half-Sleeve
    100002 Full-Sleeve
    100002 Pocket
    100002 Cuff
    100002 Cut
    100002 Cross
    100002 Slim Fit
    100002 Normal Fit
    100002 Loose Fit
    100002 Fit Knock
    100002 Button Design
    100002 Button Digit

24 rows selected.

rajesh@ORA10G>


With Table unnesting

rajesh@ORA10G> select item_id,
  2      substr( ','||style_tags||',' ,
  3                instr( ','||style_tags||',' , ',',1,column_value)+1,
  4                instr( ','||style_tags||',' , ',',1,column_value+1) -
  5                instr( ','||style_tags||',' , ',',1,column_value)-1) txt
  6  from make_item ,
  7      table(cast(multiset(select level
  8      from dual
  9      connect by level <= length(style_tags) -
 10          length(replace(style_tags,','))+1)
 11          as sys.odcinumberlist))
 12  /

   ITEM_ID TXT
---------- --------------------
    100001 Full-Sleeve
    100001 Half-Sleeve
    100001 Pocket
    100001 Cuff
    100001 Cut
    100001 Cross
    100001 Slim Fit
    100001 Normal Fit
    100001 Loose Fit
    100001 Fit Knock
    100001 Button Design
    100001 Button Digit
    100002 Full-Sleeve
    100002 Half-Sleeve
    100002 Pocket
    100002 Cuff
    100002 Cut
    100002 Cross
    100002 Slim Fit
    100002 Normal Fit
    100002 Loose Fit
    100002 Fit Knock
    100002 Button Design
    100002 Button Digit

24 rows selected.

rajesh@ORA10G>


With 12c in place, this would be a "Cross apply"

rajesh@ORA12C> select item_id,
  2    substr( ','||style_tags||',' ,
  3                instr( ','||style_tags||',' , ',',1,r)+1,
  4                instr( ','||style_tags||',' , ',',1,r+1) -
  5                instr( ','||style_tags||',' , ',',1,r)-1) txt
  6  from make_item cross apply (
  7        select level r
  8        from dual
  9        connect by level <= length(style_tags) -
 10          length( replace(style_tags,','))+1 )
 11  /

   ITEM_ID TXT
---------- --------------------
    100001 Full-Sleeve
    100001 Half-Sleeve
    100001 Pocket
    100001 Cuff
    100001 Cut
    100001 Cross
    100001 Slim Fit
    100001 Normal Fit
    100001 Loose Fit
    100001 Fit Knock
    100001 Button Design
    100001 Button Digit
    100002 Full-Sleeve
    100002 Half-Sleeve
    100002 Pocket
    100002 Cuff
    100002 Cut
    100002 Cross
    100002 Slim Fit
    100002 Normal Fit
    100002 Loose Fit
    100002 Fit Knock
    100002 Button Design
    100002 Button Digit

24 rows selected.

rajesh@ORA12C>

Connor McDonald
February 04, 2016 - 7:09 am UTC

Nice stuff.

Great Solution

Pranav Shah, February 04, 2016 - 9:22 am UTC

Hi chris i did come up with my solution tell me if this is right way to do,i am getting the result which i need.

WITH DATA AS
(SELECT item_id, style_tags str , style_tags_o str1 FROM MAKE_ITEM where item_id = 100001 )
select

ITEM_ID,
trim(regexp_substr(str, '[^,]+', 1, LEVEL)) as "STYLE_TAGS",
trim(regexp_substr(str1, '[^,]+', 1, LEVEL)) as "STYLE_TAGS_O"
from DATA
CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0


Chris Saxon
February 04, 2016 - 9:45 am UTC

If this gives the output you need and it runs "fast enough" then you're good.

Only you can answer these questions!

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.