Ok, I can try....
I usually break things down into bits and pieces to understand myself so...
ops$tkyte%ORA11GR1> select level
2 from dual
3 connect by level <= 5;
LEVEL
----------
1
2
3
4
5
<b>we can use that technique in 9ir2 and above to generate a "set", you can generate as many rows as you need that way....</b>
ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> select *
2 from table ( sys.odcivarchar2list( 'a', 'b', 'c' ) )
3 /
COLUMN_VALUE
------------------------------
a
b
c
<b>we can use the fact that there is a type defined for us in 10g that is a varchar2 type - a table of varchar2's. You could also:
create type myArray as table of varchar2(4000)
/
and use myArray instead of the sys.odcivarchar2list type.
And we use the fact that you can select from a collection using the TABLE function there</b>
ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> select *
2 from table( cast( multiset( select level from dual connect by level <= 5 ) as sys.odcivarchar2list ))
3 /
COLUMN_VALUE
------------------------------
1
2
3
4
5
<b>multiset has been around since 8.0 with the new collection types - we can take a SET and using MULTI-SET turn it into a collection. We want the collection type to be sys.odcivarchar2list, so we CAST the multiset to that type</b>
ops$tkyte%ORA11GR1> select x, column_value
2 from t, table ( sys.odcivarchar2list( t.rowid, t.x ) )
3 /
X COLUMN_VALUE
-------------------- ------------------------------
11111 AAATpPAAEAAAHdoAAA
11111 11111
101011 AAATpPAAEAAAHdoAAB
101011 101011
1000111 AAATpPAAEAAAHdoAAC
1000111 1000111
000000000111 AAATpPAAEAAAHdoAAD
000000000111 000000000111
8 rows selected.
<b>Now, we use the fact that you can use collection UN-NESTING to perform a self join of a nested table with it's source table - here I just passed the attributes rowid and x to the TABLE() function and we get two rows out for every single row in the table - each row was joined to the output of the TABLE clause</b>
ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> select rowid rid, x, to_number( substr(column_value,1,4)) lvl, substr( column_value,6,1) bit
2 from t,
3 table(
4 cast(
5 multiset( select to_char(level,'fm0000')|| '-' || substr(x,level,1)
6 from dual
7 connect by level <= length(x) ) as sys.odcivarchar2list ) )
8 /
RID X LVL B
------------------ -------------------- ---------- -
AAATpPAAEAAAHdoAAA 11111 1 1
AAATpPAAEAAAHdoAAA 11111 2 1
AAATpPAAEAAAHdoAAA 11111 3 1
AAATpPAAEAAAHdoAAA 11111 4 1
AAATpPAAEAAAHdoAAA 11111 5 1
AAATpPAAEAAAHdoAAB 101011 1 1
AAATpPAAEAAAHdoAAB 101011 2 0
AAATpPAAEAAAHdoAAB 101011 3 1
AAATpPAAEAAAHdoAAB 101011 4 0
AAATpPAAEAAAHdoAAB 101011 5 1
AAATpPAAEAAAHdoAAB 101011 6 1
AAATpPAAEAAAHdoAAC 1000111 1 1
AAATpPAAEAAAHdoAAC 1000111 2 0
AAATpPAAEAAAHdoAAC 1000111 3 0
AAATpPAAEAAAHdoAAC 1000111 4 0
AAATpPAAEAAAHdoAAC 1000111 5 1
AAATpPAAEAAAHdoAAC 1000111 6 1
AAATpPAAEAAAHdoAAC 1000111 7 1
AAATpPAAEAAAHdoAAD 000000000111 1 0
AAATpPAAEAAAHdoAAD 000000000111 2 0
AAATpPAAEAAAHdoAAD 000000000111 3 0
AAATpPAAEAAAHdoAAD 000000000111 4 0
AAATpPAAEAAAHdoAAD 000000000111 5 0
AAATpPAAEAAAHdoAAD 000000000111 6 0
AAATpPAAEAAAHdoAAD 000000000111 7 0
AAATpPAAEAAAHdoAAD 000000000111 8 0
AAATpPAAEAAAHdoAAD 000000000111 9 0
AAATpPAAEAAAHdoAAD 000000000111 10 1
AAATpPAAEAAAHdoAAD 000000000111 11 1
AAATpPAAEAAAHdoAAD 000000000111 12 1
30 rows selected.
<b>Now I've just expanded the data out - so that the bit string is running DOWN the page instead of across the page and LVL is assigned, so we can discern bit 12 from bit 11 and so on..</b>
ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> with data
2 as
3 (
4 select rowid rid, x, to_number( substr(column_value,1,4)) lvl, substr( column_value,6,1) bit
5 from t,
6 table(
7 cast(
8 multiset( select to_char(level,'fm0000')|| '-' || substr(x,level,1)
9 from dual
10 connect by level <= length(x) ) as sys.odcivarchar2list ) )
11 )
12 select data.* , replace( sys_connect_by_path( decode( bit, '1', to_char(lvl), '-' ), ' ' ), ' ', '') scbp
13 from data
14 where lvl = length(x)
15 start with lvl = 1
16 connect by prior rid = rid and prior lvl+1 = lvl
17 /
<b>if we start with lvl = 1 and connect by rowid and lvl - we can reassemble the string using sys_connect_by_path and turn '1's into the lvl and everything else into a dash - then we just keep the one row we are interested in (the last one in the hierarchy)</b>
RID X LVL B SCBP
------------------ -------------------- ---------- - ------------------------------
AAATpPAAEAAAHdoAAA 11111 5 1 12345
AAATpPAAEAAAHdoAAB 101011 6 1 1-3-56
AAATpPAAEAAAHdoAAC 1000111 7 1 1---567
AAATpPAAEAAAHdoAAD 000000000111 12 1 ---------101112