Oracle Pivot Operator

Oracle pivot operator

You are getting the output like that simply because you are issuing select statement against a table (your tbl table) which presumably contains a column(primary key column for instance) which uniquely identifies a row and pivot operator takes into consideration values of that column. Here is a simple example:

/*assume it's your table tbl */
with tbl(unique_col, col1, col2) as(
select 1, 'a', 'a1' from dual union all
select 2, 'b', 'b1' from dual union all
select 3, 'c', 'c1' from dual
)

A query against such a table will give you that output(undesirable output) you provided in the question:

select A,B 
from tbl
pivot(
max(col2) for col1 in ('a' as A,'b' as B)
)

Result:

A    B
-- --
a1 null
null b1

In order to produce desired output, you need to exclude the column with unique value for a row:

select A
, B
from (select col1
, col2 /*selecting only those columns we are interested in*/
from tbl )
pivot(
max(col2) for col1 in ('a' as A,'b' as B)
)

Result:

A  B
-- --
a1 b1

ORACLE one hot encoding: Use PIVOT operator for all available columns

You can use PL/SQL anonymous block to build the query automatically no matter how many distinct products you have in your table, but you need to understand that you can't put more than 1000 values into a pivot clause, as you can't have more than 1000 columns.

I would do something like this ( assuming always less 1000 values )

Test case ( create the table and the test values )

SQL> create table t ( CLID number , PRODUCT varchar2(10) )  ;

Table created.

SQL> insert into t ( clid , product )
2 with x ( a , b ) as
(
select 1 , 'A' from dual union all
select 1 , 'B' from dual union all
select 2 , 'A' from dual union all
select 2 , 'C' from dual union all
select 3 , 'A' from dual union all
select 3 , 'C' from dual union all
select 4 , 'D' from dual union all
select 4 , 'E' from dual union all
select 5 , 'B' from dual union all
select 5 , 'C' from dual union all
select 5 , 'D' from dual union all
select 5 , 'E' from dual
)
select a , b from x ;

12 rows created.

SQL> commit ;

Commit complete.

PLSQL construction

Then, to get automatically the query no matter how many different products

set serveroutput on size unlimited lines 220 pages 0
declare
v_query clob;
out_string varchar2(100);
cursor c_ids
is
select distinct product, count(distinct(product)) over () tot_rows from t order by 1 asc;
procedure print_clob_to_output (p_clob in clob)
is
l_offset pls_integer := 1;
l_chars pls_integer;
begin
loop
exit when l_offset > dbms_lob.getlength(p_clob);
l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
if l_chars is null or l_chars = 0 then
l_chars := dbms_lob.getlength(p_clob) + 1;
end if;
dbms_output.put_line(dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
l_offset := l_chars + 1;
end loop;
end print_clob_to_output;
begin
dbms_output.enable(null);
for item in c_ids
loop
if item.tot_rows >= 1000
then
raise_application_error(-20001,'Maximum number of 1000 columns are not allowed',true);
end if;
out_string := item.product;
if c_ids%rowcount = 1
then
v_query := 'select * from (';
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' select * ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' from t ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' pivot( ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' count(product) ');
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' for product in ( '''||out_string||''' , ');
elsif c_ids%rowcount < item.tot_rows then
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' '''||out_string||''' ,');
else
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' '''||out_string||''' ) ');
end if;
end loop;
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' ) )');
print_clob_to_output(v_query);
end;
/

Execution

SQL> @query.sql
SQL> set serveroutput on size unlimited lines 220 pages 0
SQL> declare
2 v_query clob;
3 out_string varchar2(100);
4 cursor c_ids
5 is
6 select distinct product, count(distinct(product)) over () tot_rows from t order by 1 asc;
7 procedure print_clob_to_output (p_clob in clob)
8 is
9 l_offset pls_integer := 1;
10 l_chars pls_integer;
11 begin
12 loop
13 exit when l_offset > dbms_lob.getlength(p_clob);
14 l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
15 if l_chars is null or l_chars = 0 then
16 l_chars := dbms_lob.getlength(p_clob) + 1;
17 end if;
18 dbms_output.put_line(dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
19 l_offset := l_chars + 1;
20 end loop;
21 end print_clob_to_output;
22 begin
23 dbms_output.enable(null);
24 for item in c_ids
25 loop
26 if item.tot_rows >= 1000
27 then
28 raise_application_error(-20001,'Maximum number of 1000 columns are not allowed',true);
29 end if;
30 out_string := item.product;
31 if c_ids%rowcount = 1
32 then
33 v_query := 'select * from (';
34 dbms_lob.append(v_query,''||chr(10)||'');
35 dbms_lob.append(v_query,' select * ');
36 dbms_lob.append(v_query,''||chr(10)||'');
37 dbms_lob.append(v_query,' from t ');
38 dbms_lob.append(v_query,''||chr(10)||'');
39 dbms_lob.append(v_query,' pivot( ');
40 dbms_lob.append(v_query,''||chr(10)||'');
41 dbms_lob.append(v_query,' count(product) ');
42 dbms_lob.append(v_query,''||chr(10)||'');
43 dbms_lob.append(v_query,' for product in ( '''||out_string||''' , ');
44 elsif c_ids%rowcount < item.tot_rows then
45 dbms_lob.append(v_query,''||chr(10)||'');
46 dbms_lob.append(v_query,' '''||out_string||''' ,');
47 else
48 dbms_lob.append(v_query,''||chr(10)||'');
49 dbms_lob.append(v_query,' '''||out_string||''' ) ');
50 end if;
51 end loop;
52 dbms_lob.append(v_query,''||chr(10)||'');
53 dbms_lob.append(v_query,' ) )');
54 print_clob_to_output(v_query);
55 end;
56 /
select * from (
select *
from t
pivot(
count(product)
for product in ( 'A' ,
'B' ,
'C' ,
'D' ,
'E' )
) )

PL/SQL procedure successfully completed.

SQL> select * from (
select *
from t
pivot(
count(product)
for product in ( 'A' ,
'B' ,
'C' ,
'D' ,
'E' )
) ) ;

CLID 'A' 'B' 'C' 'D' 'E'
---------- ---------- ---------- ---------- ---------- ----------
1 1 1 0 0 0
2 1 0 1 0 0
4 0 0 0 1 1
5 0 1 1 1 1
3 1 0 1 0 0

PIVOT function in Oracle 10g

Oracle 10 doesn't have pivot, so you can use conditional aggregation:

select sku,
max(case when code = 'BRAND' then value end) as brand,
max(case when code = 'CSBC' then value end) as CSBC,
max(case when code = 'DWPS' then value end) as DWPS,
max(case when code = 'DWS' then value end) as DWS,
max(case when code = 'DWSG' then value end) as DWSG,
max(case when code = 'EA' then value end) as ea
from t
group by sku;

Divide the sum of grades using pivot operator

Each student may have two marks in each subject?
Make sure of that first of all

Try to use the average AVG(Grades)

SELECT
Student, [English], [Mathematics], [Science], [Programming], [History]
FROM
(SELECT Student, Grades, Subject
FROM Grade_Report) AS SOURCETABLE
PIVOT
(AVG(Grades)
FOR Subject IN ([English], [Mathematics], [Science], [Programming],
[History])
)

Oracle SQL pivot query

Oracle 9i+ supports:

SELECT SUM(CASE WHEN t.month = 1 THEN t.value ELSE 0 END) AS JAN,
SUM(CASE WHEN t.month = 2 THEN t.value ELSE 0 END) AS FEB,
SUM(CASE WHEN t.month = 3 THEN t.value ELSE 0 END) AS MAR,
SUM(CASE WHEN t.month = 4 THEN t.value ELSE 0 END) AS APR,
SUM(CASE WHEN t.month = 5 THEN t.value ELSE 0 END) AS MAY,
SUM(CASE WHEN t.month = 6 THEN t.value ELSE 0 END) AS JUN
FROM YOUR_TABLE t

You only list two columns -- something like this should probably be grouped by year.

There is ANSI PIVOT (and UNPIVOT) syntax, but Oracle didn't support it until 11g. Prior to 9i, you'd have to replace the CASE statements with Oracle specific DECODE.

Rows to columns using PIVOT function (Oracle)

You were nearly done - the only missing point is - you should replace the MAX aggregate function with the LISTAGG function using the full syntax in the PIVOT clause.

Additionaly I adjusted the pivot column names to get nice names (without apostrophes).

See example below:

select * from (
select ID,
SUBJECT,GRADE
from tab
)
pivot
(
LISTAGG(GRADE,',') within group (order by GRADE)
for SUBJECT in
('MTH111' as MTH111,
'WRI001' as WRI001,
'PHY104' as PHY104)
)

Result as expected

ID     MTH111     WRI001     PHY104    
------ ---------- ---------- ----------
000442 B,W,W C- C,W

How can I summarize / pivot data with oracle sql

If your Oracle version is 11.1 or higher (which it should be if you are a relatively new user!) then you can use the PIVOT operator, as shown below.

Note that the result of the PIVOT operation can be given an alias (I used p) - this makes it easier to write the SELECT clause.

I assumed the name of your table is geological_data - replace it with your actual table name.

select p.*
, open_pit_tonnage + underground_tonnage as combined_tonnage
, open_pit_au_gt + underground_au_gt as combined_au_gt
, open_pit_au_oz + underground_au_oz as combined_au_oz
from geological_data
pivot (sum(tonnage) as tonnage, sum(au_gt) as au_gt, sum(au_oz) as au_oz
for area in ('Open Pit' as open_pit, 'Underground' as underground)) p
;


Related Topics



Leave a reply



Submit