First up, it's helpful to figure out what the final you want is.
To convert the numbers of pages to columns, list out all the subchapters you want to convert in your pivot clause:
CREATE TABLE t (
book_name varchar2(5), chapter varchar2(5),
subchapter varchar2(12), no_of_pages int
);
INSERT INTO t VALUES ('book1', 'chap1', 'sub_book1_a1', 230);
insert into t values ('book1', 'chap1', 'sub_book1_a2', 110);
insert into t values ('book1', 'chap1', 'sub_book1_a3', 220);
insert into t values ('book1', 'chap2', 'sub_book1_b1', 760);
insert into t values ('book1', 'chap2', 'sub_book1_b2', 530);
insert into t values ('book2', 'chap1', 'sub_book2_a1', 652);
insert into t values ('book2', 'chap1', 'sub_book2_a2', 457);
insert into t values ('book2', 'chap2', 'sub_book2_b1', 673);
select * from (
select subchapter, no_of_pages from t
)
pivot (
min(no_of_pages) for subchapter in (
'sub_book1_a1' b1a1, 'sub_book1_a2' b1a2, 'sub_book1_a3' b1a3,
'sub_book1_b1' b1b1, 'sub_book1_b2' b1b2, 'sub_book2_a1' b2a1,
'sub_book2_a2' b2a2, 'sub_book2_b1' b2b1
)
);
B1A1 B1A2 B1A3 B1B1 B1B2 B2A1 B2A2 B2B1
230 110 220 760 530 652 457 673
So you need to generate a list of all the subchapters. You can do this with plain SQL using the following listagg() statement :
select listagg('''' || subchapter || ''' as ' || subchapter, ',' || chr(10))
within group (order by subchapter) cols
from t;
COLS
'sub_book1_a1' as sub_book1_a1,
'sub_book1_a2' as sub_book1_a2,
'sub_book1_a3' as sub_book1_a3,
'sub_book1_b1' as sub_book1_b1,
'sub_book1_b2' as sub_book1_b2,
'sub_book2_a1' as sub_book2_a1,
'sub_book2_a2' as sub_book2_a2,
'sub_book2_b1' as sub_book2_b1
So to create your pivot you just need to build a dynamic string based on this.
declare
stmt varchar2(4000);
pivot_clause varchar2(1000);
begin
select listagg('''' || subchapter || ''' as ' || subchapter, ',') within group (order by subchapter)
into pivot_clause
from t
where book_name = 'book1';
stmt := 'select * from (
select book_name, subchapter, no_of_pages from t
)
pivot (
min(no_of_pages) for subchapter in (' || pivot_clause || ')
)';
dbms_output.put_line(stmt);
execute immediate stmt;
end;
/
select * from (
select book_name, subchapter, no_of_pages from t
)
pivot (
min(no_of_pages) for subchapter in ('sub_book1_a1' as sub_book1_a1,'sub_book1_a2' as sub_book1_a2,'sub_book1_a3' as sub_book1_a3,'sub_book1_b1' as sub_book1_b1,'sub_book1_b2' as sub_book1_b2)
)
There are complicating factors in your case though.
You've said you're on 10g. Pivot and listagg only came in 11g!
So instead of listagg, you could use stragg:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::p11_question_id:2196162600402 The alternative to pivot is harder. Here you need to dynamically build you select clause. Each column will be something like:
min ( case when subchapter = 'chapter name' then subchapter end ) as 'chapter name'
This would give a listagg statement like:
select listagg('min ( case when subchapter = ''' || subchapter || ''' then no_of_pages end ) as ' || subchapter, ',' || chr(10))
within group (order by subchapter) cols
from t;
COLS
min ( case when subchapter = 'sub_book1_a1' then no_of_pages end ) as sub_book1_a1,
min ( case when subchapter = 'sub_book1_a2' then no_of_pages end ) as sub_book1_a2,
min ( case when subchapter = 'sub_book1_a3' then no_of_pages end ) as sub_book1_a3,
min ( case when subchapter = 'sub_book1_b1' then no_of_pages end ) as sub_book1_b1,
min ( case when subchapter = 'sub_book1_b2' then no_of_pages end ) as sub_book1_b2,
min ( case when subchapter = 'sub_book2_a1' then no_of_pages end ) as sub_book2_a1,
min ( case when subchapter = 'sub_book2_a2' then no_of_pages end ) as sub_book2_a2,
min ( case when subchapter = 'sub_book2_b1' then no_of_pages end ) as sub_book2_b1
Use this to dynamically build a query like:
select min ( case when subchapter = 'sub_book1_a1' then no_of_pages end ) as sub_book1_a1,
min ( case when subchapter = 'sub_book1_a2' then no_of_pages end ) as sub_book1_a2,
min ( case when subchapter = 'sub_book1_a3' then no_of_pages end ) as sub_book1_a3,
min ( case when subchapter = 'sub_book1_b1' then no_of_pages end ) as sub_book1_b1,
min ( case when subchapter = 'sub_book1_b2' then no_of_pages end ) as sub_book1_b2,
min ( case when subchapter = 'sub_book2_a1' then no_of_pages end ) as sub_book2_a1,
min ( case when subchapter = 'sub_book2_a2' then no_of_pages end ) as sub_book2_a2,
min ( case when subchapter = 'sub_book2_b1' then no_of_pages end ) as sub_book2_b1
from t;
SUB_BOOK1_A1 SUB_BOOK1_A2 SUB_BOOK1_A3 SUB_BOOK1_B1 SUB_BOOK1_B2 SUB_BOOK2_A1 SUB_BOOK2_A2 SUB_BOOK2_B1
230 110 220 760 530 652 457 673
Secondly, it looks like you want to do more than a simple pivot. It seems you want to transpose the rows and columns aka a pivot + unpivot.
This is going to make your dynamic SQL harder!
For static example of how to do this, see:
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9531337800346950622