If you want to return a collection, you'd need to create a type and use collect
to populate the type.
CREATE TYPE typ_columnA_nt
AS TABLE OF <<columnA data type>>
Then you can use the collect
function
SELECT main.*
, cast( collect(SELECT columnA
FROM tableB alt
WHERE alt.columnB = main.columnB)
as typ_columnA_nt ) AS columnAs_to_tableA
FROM tableA main
If you want to return a cursor, you can use the cursor
function
SELECT main.*,
cursor( SELECT columnA
FROM tableB alt
WHERE alt.columnB = main.columnB ) as columnAs_to_tableA
FROM tableA main
If you want to return a comma-separated string, Tim Hall has a canonical list of string aggregation techniques in Oracle. In versions where listagg
is not an option, my preference would be to create a user-defined aggregate function which would allow you to
select main.*,
(select string_agg(columnA)
from tableB alt
where alt.columnB = main.columnB) as columnAs_to_tableA
from tableA main
If you are limited to solutions that don't involve creating new objects, the simplest option would be to use wm_concat
though this is not officially supported
select main.*,
(select wm_concat(columnA)
from tableB alt
where alt.columnB = main.columnB) as columnAs_to_tableA
from tableA main
If you can't create any supporting objects and you can't use unsupported functions, then you're stuck with the old row_number
and sys_connect_by_path
option which is more than a bit ugly. I think you'd want something like this but there is a decent chance that I've made a small syntax error.
select main.*,
agg.value_string
from tableA main
left join (select alt_outer.columnB,
ltrim(max(sys_connect_by_path(alt_outer.columnA,','))
keep( dense_rank last order by alt_outer.columnA ),
',') as value_string
from (select alt.columnA,
alt.columnB,
row_number() over (partition by alt.columnB
order by alt.columA) as curr,
row_number() over (partition by alt.columnB
order by alt.columA) -1 as prev
from tableB alt) alt_outer
group by alt_outer.columnB
connect by alt_outer.prev = prior alt_outer.curr
and alt_outer.columnB = prior alt_outer.columnB
start with alt_outer.curr = 1) agg
on( main.columnB = agg.columnB )
Yet another option would be to use the XML functions
SELECT main.* ,
tableB_alt.list AS columnAs_to_tableA
FROM tableA main
LEFT JOIN ( SELECT columnB ,
TRIM(TRAILING ','
FROM
XMLAGG(
XMLELEMENT(E,columnA||',')
).EXTRACT('//text()')
) list
FROM tableB
GROUP BY columnB ) tableB_alt
ON tableB_alt.columnB = main.columnB