T
This article is dedicated to my colleague and keen learner strugling today with pivot query.
This is modern version of pivot query introduced in Oracle 11g. Bad part is you have to list columns.
WITH d AS ( SELECT 'A' AS group_name, 'A' AS col_name, 10 AS col_value FROM DUAL UNION ALL SELECT 'A' AS group_name, 'B' AS col_name, 20 AS col_value FROM DUAL UNION ALL SELECT 'A' AS group_name, 'C' AS col_name, 30 AS col_value FROM DUAL UNION ALL SELECT 'A' AS group_name, 'D' AS col_name, 60 AS col_value FROM DUAL UNION ALL SELECT 'B' AS group_name, 'A' AS col_name, 10 AS col_value FROM DUAL UNION ALL SELECT 'B' AS group_name, 'B' AS col_name, 20 AS col_value FROM DUAL UNION ALL SELECT 'B' AS group_name, 'C' AS col_name, 30 AS col_value FROM DUAL ) SELECT d.* FROM d PIVOT ( SUM(d.col_value) AS sum, COUNT(d.col_value) AS count FOR col_name IN ( 'A' AS a, 'B' AS b, 'C' AS c, 'D' AS d ) ) d ORDER BY 1;
You can do dynamic columns only when output is XML.
WITH d AS ( SELECT 'A' AS group_name, 'A' AS col_name, 10 AS col_value FROM DUAL UNION ALL SELECT 'A' AS group_name, 'B' AS col_name, 20 AS col_value FROM DUAL UNION ALL SELECT 'A' AS group_name, 'C' AS col_name, 30 AS col_value FROM DUAL UNION ALL SELECT 'A' AS group_name, 'D' AS col_name, 60 AS col_value FROM DUAL UNION ALL SELECT 'B' AS group_name, 'A' AS col_name, 10 AS col_value FROM DUAL UNION ALL SELECT 'B' AS group_name, 'B' AS col_name, 20 AS col_value FROM DUAL UNION ALL SELECT 'B' AS group_name, 'C' AS col_name, 30 AS col_value FROM DUAL ) SELECT d.group_name, TRIM(d.col_name_xml) AS xml FROM d PIVOT XML ( -- XML SUM(col_value) AS sum, COUNT(col_value) AS count FOR col_name IN ( SELECT DISTINCT d.col_name -- dynamic columns possible in XML only FROM d ) ) d ORDER BY 1;
You can convert XML back to table.
SELECT * FROM XMLTABLE ( '/PivotSet/item' PASSING XMLTYPE('') COLUMNS col_name VARCHAR2(30) PATH 'column[@name="COL_NAME"]', sum_ NUMBER PATH 'column[@name="SUM"]', count_ NUMBER PATH 'column[@name="COUNT"]' ); A 10 1 B 20 1 C 30 1 D 60 1
You can also convert it to JSON.
SELECT JSON_OBJECTAGG(col_name VALUE JSON_OBJECT('SUM' VALUE sum_, 'COUNT' VALUE count_)) AS json FROM XMLTABLE ( '/PivotSet/item' PASSING XMLTYPE('') COLUMNS col_name VARCHAR2(30) PATH 'column[@name="COL_NAME"]', sum_ NUMBER PATH 'column[@name="SUM"]', count_ NUMBER PATH 'column[@name="COUNT"]' ); A 10 1 B 20 1 C 30 1 D 60 1
And of course you can reverse pivoted table.
WITH d AS ( SELECT 'A' AS group_name, 11 AS col_a, 12 AS col_b, 13 AS col_c, 14 AS col_d FROM DUAL UNION ALL SELECT 'B' AS group_name, 21 AS col_a, 22 AS col_b, 23 AS col_c, 24 AS col_d FROM DUAL ) SELECT * FROM d UNPIVOT ( col_value FOR col_name IN ( col_a AS 'A', col_b AS 'B', col_c AS 'C', col_d AS 'D' ) );
Thank you! I do understand it better now.
ReplyDeleteThe colleague.