Reputation: 192
In Postgres, I would do this:
SELECT main.*
, array(SELECT columnA FROM tableB alt WHERE alt.columnB = main.columnB) AS columnAs_to_tableA
FROM tableA main
How might one do the same in Oracle 10? It should be noted that I cannot use the listagg. I found this answer to a similar question: Aggregate String Concatenation in Oracle 10g I have NO clue how this answer is working at all, nor if this really is the "correct" solution, because it was never marked as answered/accepted.
I feel like answering this with an example using the same table names I provided for a one-to-one comparison might work best for others seeking the same answer.
Thank You
EDIT 1: I should add that I want to avoid introducing new schema elements, like tables, functions, etc...
EDIT 2: Removing the requirement for the array. a comma delimited string will suffice.
Upvotes: 0
Views: 278
Reputation: 231781
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
Upvotes: 2