Pivot queries retun NULL when there's no row to be pivoted.
in the following example the COLOR attribute is missing for id=2.
with src_data (id, attr_name, attr_id, attr_type) as (
select 1, 'ITALY', 'IT', 'COUNTRY' FROM DUAL UNION ALL --
select 1, 'GREEN', 'G', 'COLOR' FROM DUAL UNION ALL --
select 1, 'BIG', 'B', 'SIZE' FROM DUAL UNION ALL --
select 2, 'FRANCE', 'FR', 'COUNTRY' FROM DUAL UNION ALL --
select 2, 'SMALL', 'S', 'SIZE' FROM DUAL --
)
select * from src_data
PIVOT (MAX(ATTR_NAME) AS NAME, MAX(ATTR_ID) AS ID --
FOR attr_type IN ('COUNTRY' AS "COUNTRY", 'COLOR' AS "COLOR", 'SIZE' AS "SIZE"));
the result is
| ID | COUNTRY_NAME | COUNTRY_ID | COLOR_NAME | COLOR_ID | SIZE_NAME | SIZE_ID |
|---|---|---|---|---|---|---|
| 1 | ITALY | IT | GREEN | G | BIG | B |
| 2 | FRANCE | FR | NULL | NULL | SMALL | S |
I would like to replace those null values with specific values (e.g. use N/D for the name and -1 for the id).
the naive attempts do not work
PIVOT (NVL(MAX(ATTR_NAME), 'N/D') AS NAME ...givesORA-56902: expect aggregate function inside pivot operationPIVOT (MAX(NVL(ATTR_NAME, 'N/D')) AS NAME ...still gives null results. My interpretation is that that NVL is never even called, since there's no row at all to be called on (whereATTR_TYPE = 'COLOR' AND ID = 2)
The very ugly solutions I see are
- adding the specific
NVLlogic on all the columns produced byPIVOT. My real life case has 14 such columns. - adding fake rows to the
PIVOTinput to cover such cases
any better ideas?
--- edit ---
Looks like the native pivot cannot do this. The best I could do is adding the missing rows with an outer join and the having the nvl on the real NULLs returned by the outer join
with src_data (id, attr_name, attr_id, attr_type) as (
select 1, 'ITALY', 'IT', 'COUNTRY' FROM DUAL UNION ALL
select 1, 'GREEN', 'G', 'COLOR' FROM DUAL UNION ALL
select 1, 'BIG', 'B', 'SIZE' FROM DUAL UNION ALL
select 2, 'FRANCE', 'FR', 'COUNTRY' FROM DUAL UNION ALL
select 2, 'SMALL', 'S', 'SIZE' FROM DUAL
),
src_ids_types as (
select src_ids.id, src_types.attr_type
from (select distinct id from src_data) src_ids
cross join (select distinct attr_type from src_data) src_types
),
full_data as (
select sit.id, sit.attr_type, d.attr_name, d.attr_id
from src_ids_types sit
left outer join src_data d on d.id = sit.id and d.attr_type = sit.attr_type
)
select *
from full_data d
PIVOT (MAX(NVL(ATTR_NAME, 'N/D')) AS NAME, MAX(NVL(ATTR_ID, -1)) AS ID --
FOR attr_type IN ('COUNTRY' AS "COUNTRY", 'COLOR' AS "COLOR", 'SIZE' AS "SIZE"))