Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Sankar.

Asked: June 06, 2006 - 10:32 pm UTC

Last updated: June 07, 2006 - 1:29 pm UTC

Version: 10.1

Viewed 1000+ times

You Asked

Hi Tom,

I have comma separated values in the cell. Now I want to display each CSV in a separate row. For example

CSV Desired Output
----------------------------------------------
123,354354,45353,83457439 123
123,354354,45353,83457439 354354
123,354354,45353,83457439 45353
123,354354,45353,83457439 83457439

I got the desired result by using the following query:

select CSV,
substr(CSV,
decode(rownum,
1,
1,
instr(CSV || ',', ',', 1, rownum - 1) + 1),
(instr(CSV || ',', ',', 1, rownum) - 1) -
decode(rownum,
1,
1,
instr(CSV || ',', ',', 1, rownum - 1) + 1) + 1) Value
from (select '123,354354,45353,83457439' CSV
from dual)
connect by rownum < length(CSV) - length(replace(CSV, ',', '')) + 1


My question is, How can I accomplish the same result using Model Clause of 10g

Thanks in advance
Sankar


and Tom said...

why, you have the right approach already.

</code> http://asktom.oracle.com/Misc/varying-in-lists.html <code>

you did it the way I would do it...

We are done, don't need or want the model clause in this case.

Rating

  (3 ratings)

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

Comments

To Learn a new thing

Sankar, May 07, 2007 - 2:07 pm UTC

Hi Tom,

I would like to learn all the possible uses of Model clause.Please give me an example to accomplish the result using model clause.

Thanks in Advance,
Sankar

MODEL to pivot

Duke Ganote, January 09, 2008 - 9:21 am UTC

Anthony Molinaro's book "SQL Cookbook" has an example of pivoting a CSV using MODEL:
http://www.oreillynet.com/pub/a/network/2004/08/10/MODELclause.html?page=3

RE: To Learn a new thing

Duke Ganote, January 25, 2012 - 3:11 pm UTC

The original query is nicely dense. However, a MODEL approach offers some advantages.

First, I "unwrapped" the original query into a modular (but not MODEL) approach:

WITH
sample_Data AS (
SELECT '123,354354,45353,83457439' AS csv
FROM DUAL
),
data_plus AS (
SELECT csv
, LENGTH(CSV) - LENGTH(REPLACE(CSV, ',', '')) + 1 AS comma_cnt
FROM sample_data
),
data_columnized AS (
SELECT csv, LEVEL as part#
FROM data_plus
CONNECT BY level <= comma_cnt
)
SELECT csv, substr(CSV,
decode(part#,
1,
1,
instr(CSV || ',', ',', 1, part# - 1) + 1),
(instr(CSV || ',', ',', 1, part#) - 1) -
decode(part#,
1,
1,
instr(CSV || ',', ',', 1, part# - 1) + 1) + 1) Value
FROM data_columnized
ORDER BY part#

That final SELECT is still pretty dense code to read.

By contrast, an approach using MODEL may be easier to debug:
(1) you can "see all the parts" without redundant code,
(2) it may be a more familiar recursive style.

In the following query, I used MODEL for the final SELECT. I commented out the "helper" columns, but they're easily available for debugging:

WITH
sample_Data AS (
SELECT '123,354354,45353,83457439' AS csv
FROM DUAL
),
data_plus AS (
SELECT csv
, LENGTH(CSV) - LENGTH(REPLACE(CSV, ',', '')) + 1 AS comma_cnt
FROM sample_data
),
data_columnized AS (
SELECT csv, LEVEL as part#
FROM data_plus
CONNECT BY level <= comma_cnt
)
SELECT csv, part_csv--part#, input_csv, output_csv
FROM data_columnized
MODEL DIMENSION BY (part#)
MEASURES ( csv
, cast(null as varchar2(20)) AS part_csv
, cast(null as varchar2(50)) AS input_csv
, cast(null as varchar2(50)) AS output_csv
, cast(null as number) AS decomma_pos#
)
RULES AUTOMATIC ORDER
( input_csv[part#] = CASE CV(part#)
WHEN 1 THEN csv[cv()]||','
ELSE output_csv[CV()-1]
END
, decomma_pos#[part#] = INSTR(input_csv[cv()],',')
, part_csv[part#] = SUBSTR(input_csv[cv()],1,decomma_pos#[cv()]-1)
, output_csv[part#] = SUBSTR(input_csv[cv()],decomma_pos#[cv()]+1)
)
ORDER BY part#