Custom Objects in Fusion SaaS are very useful feature allowing customers to add their own data and use it together with existing Oracle provided seeded tables.
In the past we have published a solution that allows writing environment independent SQL based BIP reports that can be easily moved between environments.
The method is described here https://cidsolutions.com/2023/11/15/improved-method-for-writing-instance-independent-sql-queries-over-custom-objects-in-fusion-saas/ .
The solution above utilizes XML Query feature of Oracle database.
This post will show even more efficient approach using lexical feature of BI Publisher.
The new approach uses native SQL without XMLQuery parsing and much more efficient in performance.
There are still places like bursting that we can not use the new proposed approach and should still use the XML Query feature.
Thanks to @serhii (Serhii Kononov) for contributing to the solution.
with custom_objects as (
select 'ACSFDCQuotes_c' custom_object, 'Currency_code_c,Delivery_terms_c,Expiration_date_c' columns, 'ID,RECORD_NAME' std_fields from dual union all
select 'SFDCQuoteLines_c' custom_object, 'ACSFDCQuotes_Id_c,Discount%' columns, null std_fields from dual union all
select 'OSS_COVERAGE_HEADERS' custom_object, 'CoverageType_c' columns, 'COVERAGE_HEADER_ID' std_fields from dual
),
codes as (
select co.custom_object custom_object,
code
from custom_objects co,
adf_extensible_table_usage tu,
lateral(
select 'select ' ||
any_value(co.std_fields) || case when any_value(co.std_fields) is not null and any_value(co.std_fields) not like '%,' then ', ' end ||
listagg(def.column_name || ' ' || def.attribute_name, ',') within group (order by def.attribute_name) ||
' from ' || any_value(def.table_name) ||
case when any_value(tu.context_column_value) is not null then ' where attribute_category = ''' || any_value(tu.context_column_value) || '''' end code
from (
select c.column_name, cu.attribute_name, t.table_name
from adf_extensible_table t,
adf_extension_column c,
adf_extension_column_usage cu
where (t.table_name = co.custom_object or cu.table_usage_id = tu.usage_id)
and c.table_id = t.table_id
and cu.column_id = c.column_id
and t.sandbox_name is null
and c.sandbox_name is null
and exists (
select 1
from (
select regexp_substr(co.columns, '[^,]+', 1, level) requested_column_mask from dual connect by regexp_substr(co.columns, '[^,]+', 1, level) is not null
) where cu.attribute_name like requested_column_mask
)
) def
)
where tu.context_column_value (+)= co.custom_object
)
select *
from (
select custom_object custom_object_name, code
from codes
)
pivot (
any_value(code) for
custom_object_name in (
'ACSFDCQuotes_c' as "ACSFDCQuotes_code",
'SFDCQuoteLines_c' as "SFDCQuoteLines_code",
'OSS_COVERAGE_HEADERS' as "OSS_COVERAGE_HEADERS_code"
)
)

ACSFDCQuotes_code) or (&OSS_COVERAGE_HEADERS_code).

