I have data in a table as seen below:
MONTH VALUE
1 100
2 200
3 300
4 400
5 500
6 600
I want to write a SQL query so that result is given as below:
MONTH_JAN MONTH_FEB MONTH_MAR MONTH_APR MONTH_MAY MONTH_JUN
100 200 300 400 500 600
Oracle 11g and above
As of Oracle 11g, you can now use the PIVOT operator to achieve that result:
create table tq84_pivot (
month number,
value number
);
insert into tq84_pivot values(1, 100);
insert into tq84_pivot values(2, 200);
insert into tq84_pivot values(3, 300);
insert into tq84_pivot values(4, 400);
insert into tq84_pivot values(5, 500);
insert into tq84_pivot values(6, 600);
--
insert into tq84_pivot values(1, 400);
insert into tq84_pivot values(2, 350);
insert into tq84_pivot values(4, 150);
select
*
from
tq84_pivot
pivot (
sum (value) as sum_value for
(month) in (1 as month_jan,
2 as month_feb,
3 as month_mar,
4 as month_apr,
5 as month_mai,
6 as month_jun,
7 as month_jul,
8 as month_aug,
9 as month_sep,
10 as month_oct,
11 as month_nov,
12 as month_dec)
);
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.
Dynamic Pivot for Oracle 11g+
There’s no straightforward method for dynamic pivoting in Oracle’s SQL, unless it returns XML type results.
For the non-XML results PL/SQL might be used through creating functions of SYS_REFCURSOR return type
With PIVOT Clause
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ''''||month||''' AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT *
FROM tab t
PIVOT
(
MAX(value) FOR month IN ( '|| v_cols ||' )
)';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
With Conditional Aggregation
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX( CASE WHEN month = '''||month||''' THEN '||value||' END ) AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT '|| v_cols ||' FROM tab';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
and then the function can be invoked as
VAR rc REFCURSOR
EXEC :rc := Get_Month_Values;
PRINT rc
from SQL Developer's command line
Demo
how to get pivot of the table
SELECT *
FROM Product
PIVOT (MAX(VALUE) FOR (P_name, P_id) IN ((choclate,6) AS choclate_6, (candies,8) AS candies_8,
(Biscuits,9) AS Biscuits_9)
Related
I have table as -
filename description value
-------- ------------------------------------------ --------------------
rec_123 PropertyWriteCount_rows_0_month February 2018
rec_123 rows_PropertyWriteCount_rows_0_description property write count
rec_123 PropertyWriteCount_rows_0_value_value 1234
rec_123 PropertyWriteCount_rows_0_value_baseType LONG
I want to convert it into -
filename month value description value_basetype
-------- ------------- ----- ------------------------- --------------
rec_2134 February 2018 1234 PropertyWriteCount_rows_0 long
I could able to write PL/SQL till this point, need help for next steps -
CREATE PROCEDURE rows_column IS
CURSOR get_rows IS
SELECT * FROM table1 where description LIKE 'PropertyWriteCount_rows%';
BEGIN
DBMS_OUTPUT.PUT_LINE('table info -');
END;
/
You can do this with conditional aggregation:
select
filename,
max(case when description = 'PropertyWriteCount_rows_0_month' then value end) as month,
max(case when description = 'rows_PropertyWriteCount_rows_0_description' then value end) as description,
max(case when description = 'PropertyWriteCount_rows_0_value_value' then value end) as value,
max(case when description = 'PropertyWriteCount_rows_0_value_baseType' then value end) as value_basetype
from table1
where description like '%PropertyWriteCount_rows%'
group by filename
You can use PIVOT clause after rendering description column in order to extract the last word after last underscore from that column.
The following query might be used as a static approach
SELECT *
FROM
(
SELECT REGEXP_SUBSTR(description,'[^_]+$') AS title,
filename, value
FROM table1 )
PIVOT
(
MAX(value) FOR title IN ('month' AS month, 'value' AS value,
'description' AS description, 'baseType' AS baseType)
)
Demo
but a dynamic approach should be preferred rather, through creating a stored function as in the following PL/SQL code
CREATE OR REPLACE FUNCTION Get_File_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_col VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ''''||titles||''' AS '||titles , ',' )
WITHIN GROUP ( ORDER BY titles DESC )
INTO v_col
FROM ( SELECT DISTINCT REGEXP_SUBSTR(description,'[^_]+$') AS titles
FROM table1 );
v_sql :=
'SELECT *
FROM (
SELECT REGEXP_SUBSTR(description,''[^_]+$'') AS title,
filename, value
FROM table1
)
PIVOT
(
MAX(value) FOR title IN ( '|| v_col ||' )
)';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
Then running the below code :
VAR rc REFCURSOR
EXEC :rc := Get_File_Values;
PRINT rc
from SQL Developer's Command Line
or
BEGIN
:result := Get_File_Values;
END;
from Test window of PL/SQL Developer (as tagged)
in order to see the expected result set varying even if the new values for description column are inserted or some former values are deleted.
i need help to transpose a table but just using one column and replicate information from another column.
UPDATE
I have this query:
CREATE SEQUENCE SEQ_document MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 2206 NOCACHE ORDER NOCYCLE NOKEEP NOSCALE GLOBAL;
CREATE TABLE ALL_DOCUMENT (
ID NUMBER(19,0) DEFAULT SEQ_document.nextval NOT NULL
,ART_DOC VARCHAR2(256 CHAR)
,TYPE_DOC VARCHAR2(256 BYTE)
,DATE_DOC TIMESTAMP(6)
,VALUE_DOC NUMBER(19,6)
,TABLENAME_DOC VARCHAR2(256 BYTE)
);
INSERT INTO "MIBDES"."ALL_DOCUMENT" (ART_DOC, TYPE_DOC, DATE_DOC, VALUE_DOC, TABLENAME_DOC) VALUES ('A00', '35', TO_TIMESTAMP('2020-04-30 13:49:24.330761000', 'YYYY-MM-DD HH24:MI:SS.FF'), '9,7599', 'table_1');
INSERT INTO "MIBDES"."ALL_DOCUMENT" (ART_DOC, TYPE_DOC, DATE_DOC, VALUE_DOC, TABLENAME_DOC) VALUES ('A00', '75', TO_TIMESTAMP('2020-03-14 13:50:02.312782000', 'YYYY-MM-DD HH24:MI:SS.FF'), '13,6562', 'table_2');
INSERT INTO "MIBDES"."ALL_DOCUMENT" (ART_DOC, TYPE_DOC, DATE_DOC, VALUE_DOC, TABLENAME_DOC) VALUES ('A00', '35', TO_TIMESTAMP('2020-03-4 13:50:02.312782000', 'YYYY-MM-DD HH24:MI:SS.FF'), '6,9978', 'table_2');
INSERT INTO "MIBDES"."ALL_DOCUMENT" (ART_DOC, TYPE_DOC, DATE_DOC, VALUE_DOC, TABLENAME_DOC) VALUES ('A00', '16', TO_TIMESTAMP('2020-04-8 13:50:02.312782000', 'YYYY-MM-DD HH24:MI:SS.FF'), '4,7851', 'table_3');
commit;
The idea or requirement is get this:
And i don't have a clear idea how to make this transpose. Can somebody give me a hand?
Best Regards
Do the columns table_1 and table_2 display the same value in all rows?
The following subquery to use CASE expression and MAX function can get one row.
Then you can get your expected result by joining the row and ALL_DOCUMENT table.
SELECT ART_DOC,TYPE_DOC,DATE_DOC,"table_1","table_2"
FROM ALL_DOCUMENT CROSS JOIN
(SELECT
MAX(CASE WHEN TABLENAME_DOC='table_1' THEN VALUE_DOC END) AS "table_1",
MAX(CASE WHEN TABLENAME_DOC='table_2' THEN VALUE_DOC END) AS "table_2"
FROM ALL_DOCUMENT) T;
dbfiddle
In case of your updated question, the query is below:
SELECT ART_DOC,TYPE_DOC,
MAX(CASE WHEN TABLENAME_DOC='table_1' THEN VALUE_DOC END) AS "table_1",
MAX(CASE WHEN TABLENAME_DOC='table_2' THEN VALUE_DOC END) AS "table_2",
MAX(CASE WHEN TABLENAME_DOC='table_3' THEN VALUE_DOC END) AS "table_3"
FROM ALL_DOCUMENT
GROUP BY ART_DOC,TYPE_DOC
ORDER BY "table_1","table_2","table_3";
You can get VALUE_DOCs of each TABLENAME_DOC using by GROUP BY clause and MAX function with CASE expression.
dbfiddle
Basically there are two methods for pivoting within Oracle's SQL :
Using Conditional Aggregation :
While you can pivot the resulting columns as
SELECT art_doc, type_doc,
MAX(CASE WHEN tablename_doc = 'table_1' THEN value_doc END) AS "table_1",
MAX(CASE WHEN tablename_doc = 'table_2' THEN value_doc END) AS "table_2",
MAX(CASE WHEN tablename_doc = 'table_3' THEN value_doc END) AS "table_3"
FROM all_document
GROUP BY art_doc, type_doc;
this is the static method, you'd better prefering the dynamic method through creating a function returning value of type SYS_REFCURSOR such as
CREATE OR REPLACE FUNCTION Get_Pivoted_Documents RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( 'MAX(CASE WHEN tablename_doc = '''||tablename_doc||''' THEN value_doc END) AS "'||tablename_doc||'"' , ',' )
WITHIN GROUP ( ORDER BY TO_NUMBER( REGEXP_REPLACE(tablename_doc,'[^0-9]') ) )
INTO v_cols
FROM (
SELECT DISTINCT tablename_doc
FROM all_document
);
v_sql :=
'SELECT art_doc , type_doc, '|| v_cols ||'
FROM all_document
GROUP BY art_doc , type_doc';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
Using PIVOT Clause :
with static method ;
SELECT art_doc , type_doc,
MAX("table_1") AS "table_1",
MAX("table_2") AS "table_2",
MAX("table_3") AS "table_3"
FROM all_document
PIVOT
(
MAX(value_doc) FOR tablename_doc IN ('table_1' AS "table_1",'table_2' AS "table_2",'table_3' AS "table_3")
)
GROUP BY art_doc , type_doc;
with dynamic method :
CREATE OR REPLACE FUNCTION Get_Pivoted_Documents RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols_1 VARCHAR2(32767);
v_cols_2 VARCHAR2(32767);
BEGIN
SELECT LISTAGG( 'MAX("'||tablename_doc||'") AS "'||tablename_doc||'"' , ',' )
WITHIN GROUP ( ORDER BY TO_NUMBER( REGEXP_REPLACE(tablename_doc,'[^0-9]') ) )
INTO v_cols_1
FROM (
SELECT DISTINCT tablename_doc
FROM all_document
);
SELECT LISTAGG( ''''||tablename_doc||''' AS "'||tablename_doc||'"' , ',' )
WITHIN GROUP ( ORDER BY TO_NUMBER( REGEXP_REPLACE(tablename_doc,'[^0-9]') ) )
INTO v_cols_2
FROM (
SELECT DISTINCT tablename_doc
FROM all_document
);
v_sql :=
'SELECT art_doc , type_doc, '|| v_cols_1 ||'
FROM all_document
PIVOT
(
MAX(value_doc) FOR tablename_doc IN ( '|| v_cols_2 ||' )
)
GROUP BY art_doc , type_doc';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
and then revoke from SQL Developer's console as
SQL> DECLARE
result SYS_REFCURSOR;
BEGIN
:result := Get_Pivoted_Documents;
END;
/
SQL> PRINT result ;
or from PL/SQL Developer's Test Window :
begin
-- Call the function
:result := get_pivoted_documents; --> yields Value of type <Cursor>
end;
I have data in a table as seen below:
MONTH VALUE
1 100
2 200
3 300
4 400
5 500
6 600
I want to write a SQL query so that result is given as below:
MONTH_JAN MONTH_FEB MONTH_MAR MONTH_APR MONTH_MAY MONTH_JUN
100 200 300 400 500 600
Oracle 11g and above
As of Oracle 11g, you can now use the PIVOT operator to achieve that result:
create table tq84_pivot (
month number,
value number
);
insert into tq84_pivot values(1, 100);
insert into tq84_pivot values(2, 200);
insert into tq84_pivot values(3, 300);
insert into tq84_pivot values(4, 400);
insert into tq84_pivot values(5, 500);
insert into tq84_pivot values(6, 600);
--
insert into tq84_pivot values(1, 400);
insert into tq84_pivot values(2, 350);
insert into tq84_pivot values(4, 150);
select
*
from
tq84_pivot
pivot (
sum (value) as sum_value for
(month) in (1 as month_jan,
2 as month_feb,
3 as month_mar,
4 as month_apr,
5 as month_mai,
6 as month_jun,
7 as month_jul,
8 as month_aug,
9 as month_sep,
10 as month_oct,
11 as month_nov,
12 as month_dec)
);
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.
Dynamic Pivot for Oracle 11g+
There’s no straightforward method for dynamic pivoting in Oracle’s SQL, unless it returns XML type results.
For the non-XML results PL/SQL might be used through creating functions of SYS_REFCURSOR return type
With PIVOT Clause
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ''''||month||''' AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT *
FROM tab t
PIVOT
(
MAX(value) FOR month IN ( '|| v_cols ||' )
)';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
With Conditional Aggregation
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX( CASE WHEN month = '''||month||''' THEN '||value||' END ) AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT '|| v_cols ||' FROM tab';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
and then the function can be invoked as
VAR rc REFCURSOR
EXEC :rc := Get_Month_Values;
PRINT rc
from SQL Developer's command line
Demo
how to get pivot of the table
SELECT *
FROM Product
PIVOT (MAX(VALUE) FOR (P_name, P_id) IN ((choclate,6) AS choclate_6, (candies,8) AS candies_8,
(Biscuits,9) AS Biscuits_9)
I have data in a table as seen below:
MONTH VALUE
1 100
2 200
3 300
4 400
5 500
6 600
I want to write a SQL query so that result is given as below:
MONTH_JAN MONTH_FEB MONTH_MAR MONTH_APR MONTH_MAY MONTH_JUN
100 200 300 400 500 600
Oracle 11g and above
As of Oracle 11g, you can now use the PIVOT operator to achieve that result:
create table tq84_pivot (
month number,
value number
);
insert into tq84_pivot values(1, 100);
insert into tq84_pivot values(2, 200);
insert into tq84_pivot values(3, 300);
insert into tq84_pivot values(4, 400);
insert into tq84_pivot values(5, 500);
insert into tq84_pivot values(6, 600);
--
insert into tq84_pivot values(1, 400);
insert into tq84_pivot values(2, 350);
insert into tq84_pivot values(4, 150);
select
*
from
tq84_pivot
pivot (
sum (value) as sum_value for
(month) in (1 as month_jan,
2 as month_feb,
3 as month_mar,
4 as month_apr,
5 as month_mai,
6 as month_jun,
7 as month_jul,
8 as month_aug,
9 as month_sep,
10 as month_oct,
11 as month_nov,
12 as month_dec)
);
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.
Dynamic Pivot for Oracle 11g+
There’s no straightforward method for dynamic pivoting in Oracle’s SQL, unless it returns XML type results.
For the non-XML results PL/SQL might be used through creating functions of SYS_REFCURSOR return type
With PIVOT Clause
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ''''||month||''' AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT *
FROM tab t
PIVOT
(
MAX(value) FOR month IN ( '|| v_cols ||' )
)';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
With Conditional Aggregation
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX( CASE WHEN month = '''||month||''' THEN '||value||' END ) AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT '|| v_cols ||' FROM tab';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
and then the function can be invoked as
VAR rc REFCURSOR
EXEC :rc := Get_Month_Values;
PRINT rc
from SQL Developer's command line
Demo
how to get pivot of the table
SELECT *
FROM Product
PIVOT (MAX(VALUE) FOR (P_name, P_id) IN ((choclate,6) AS choclate_6, (candies,8) AS candies_8, (Biscuits,9) AS Biscuits_9)
I have data in a table as seen below:
MONTH VALUE
1 100
2 200
3 300
4 400
5 500
6 600
I want to write a SQL query so that result is given as below:
MONTH_JAN MONTH_FEB MONTH_MAR MONTH_APR MONTH_MAY MONTH_JUN
100 200 300 400 500 600
Oracle 11g and above
As of Oracle 11g, you can now use the PIVOT operator to achieve that result:
create table tq84_pivot (
month number,
value number
);
insert into tq84_pivot values(1, 100);
insert into tq84_pivot values(2, 200);
insert into tq84_pivot values(3, 300);
insert into tq84_pivot values(4, 400);
insert into tq84_pivot values(5, 500);
insert into tq84_pivot values(6, 600);
--
insert into tq84_pivot values(1, 400);
insert into tq84_pivot values(2, 350);
insert into tq84_pivot values(4, 150);
select
*
from
tq84_pivot
pivot (
sum (value) as sum_value for
(month) in (1 as month_jan,
2 as month_feb,
3 as month_mar,
4 as month_apr,
5 as month_mai,
6 as month_jun,
7 as month_jul,
8 as month_aug,
9 as month_sep,
10 as month_oct,
11 as month_nov,
12 as month_dec)
);
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.
Dynamic Pivot for Oracle 11g+
There’s no straightforward method for dynamic pivoting in Oracle’s SQL, unless it returns XML type results.
For the non-XML results PL/SQL might be used through creating functions of SYS_REFCURSOR return type
With PIVOT Clause
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ''''||month||''' AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT *
FROM tab t
PIVOT
(
MAX(value) FOR month IN ( '|| v_cols ||' )
)';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
With Conditional Aggregation
CREATE OR REPLACE FUNCTION Get_Month_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG('MAX( CASE WHEN month = '''||month||''' THEN '||value||' END ) AS "MONTH_'||TO_CHAR( TO_DATE(month,'mm') ,'MON')||'"' , ',' )
WITHIN GROUP ( ORDER BY month )
INTO v_cols
FROM tab;
v_sql :='SELECT '|| v_cols ||' FROM tab';
OPEN v_recordset FOR v_sql;
DBMS_OUTPUT.PUT_LINE(v_sql);
RETURN v_recordset;
END;
/
and then the function can be invoked as
VAR rc REFCURSOR
EXEC :rc := Get_Month_Values;
PRINT rc
from SQL Developer's command line
Demo
how to get pivot of the table
SELECT *
FROM Product
PIVOT (MAX(VALUE) FOR (P_name, P_id) IN ((choclate,6) AS choclate_6, (candies,8) AS candies_8, (Biscuits,9) AS Biscuits_9)