Reputation: 67
I'm trying to use pivot to accomplish the following:
The data in the source table looks like:
Company | Company ID | Product Code | Product Unit | Reporting Year | Value |
---|---|---|---|---|---|
a | 1 | dd | gln | 2019 | 7 |
a | 1 | dd | gln | 2020 | 2 |
b | 2 | bb | kg | 2021 | 3 |
The data in the pivoted table should look like:
Company | Company ID | Product Code | Product Unit | 2019 | 2020 | 2021 |
---|---|---|---|---|---|---|
a | 1 | dd | gln | 7 | 2 | |
b | 2 | bb | kg | 3 |
I tried and it did not work:
select * from source pivot ( max(value) for year in (2019,2020,2021) );
Any help greatly appreciated.
Upvotes: 0
Views: 778
Reputation:
You were almost there:
select * from source pivot ( max(Value) for "Reporting Year" in (2019,2020,2021) );
Please note that Oracle does not allow column names with spaces, so the space there should be replaced with an underscore, for example.
Thus, the query would be:
select * from source pivot ( max(Value) for "Reporting_Year" in (2019,2020,2021) );
Upvotes: 0
Reputation: 65433
No need to specify all the years within the PIVOT clause's list by using a dynamical code structure , assuming that you have only those three year values within the table currently, and propagate to the new pivoted columns along with the newly inserted upcoming year values through creating a stored function such as
CREATE OR REPLACE FUNCTION Fn_Pivot_Table RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ReportingYear , ',') WITHIN GROUP ( ORDER BY ReportingYear )
INTO v_cols
FROM ( SELECT DISTINCT ReportingYear FROM source );
v_sql :='SELECT *
FROM source
PIVOT(
MAX(Value) FOR ReportingYear IN (' || v_cols ||' )
)
ORDER BY CompanyID';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
which might be invoked from the SQL Developer's console as
SQL> DECLARE
result SYS_REFCURSOR;
BEGIN
:result := Fn_Pivot_Table;
END;
/
SQL> PRINT result;
Upvotes: 1
Reputation: 168796
Change year
to reportingyear
and your code appears to work:
select * from source pivot ( max(value) for reportingyear in (2019,2020,2021) );
Which, for the sample data:
CREATE TABLE source ( Company, CompanyID, ProductCode, ProductUnit, ReportingYear, Value ) AS
SELECT 'a', 1, 'dd', 'gln', 2019, 7 FROM DUAL UNION ALL
SELECT 'a', 1, 'dd', 'gln', 2020, 2 FROM DUAL UNION ALL
SELECT 'b', 2, 'bb', 'kg', 2021, 3 FROM DUAL
Outputs:
COMPANY COMPANYID PRODUCTCODE PRODUCTUNIT 2019 2020 2021 b 2 bb kg <null> <null> 3 a 1 dd gln 7 2 <null>
If you are using quoted identifiers and have a space in the column name then you need to use a quoted identifier every time you refer to that column:
select * from source pivot ( max(value) for "Reporting Year" in (2019,2020,2021) );
db<>fiddle here
Upvotes: 2
Reputation: 1271191
Just use conditional aggregation:
select Company, Company_ID, Product_Code, Product_Unit,
sum(case when year = 2019 then value else 0 end) as val_2019,
sum(case when year = 2020 then value else 0 end) as val_2020,
sum(case when year = 2021 then value else 0 end) as val_2021
from source
group by Company, Company_ID, Product_Code, Product_Unit;
Upvotes: 1