This is an interesting and difficult problem, obscured by your poor data model (which violates First Normal Form). Normalizing the data - and de-normalizing at the end - is trivial, it's just an annoyance (and it will make the query much slower). The interesting part: the input groups are the nodes of a graph, two nodes are connected if they have a "make" in common. You need to find the connected components of the graph; this is the interesting problem.
Here is a complete solution (creating the testing data on the fly, in the first factored subquery in the with
clause). Question for you though: even assuming that this solution works for you and you put it in production, who is going to maintain it in the future?
EDIT It occurred to me that my original query can be simplified. Here is the revised version; you can click on the Edited link below the answer if you are curious to see the original version.
with
sample_data (brand) as (
select 'Audi, Opel, Ford' from dual union all
select 'Skoda, Renault' from dual union all
select 'Audi, BMW' from dual union all
select 'Audi, Volkswagen, Opel' from dual union all
select 'Toyota, Hyundai' from dual union all
select 'Tesla' from dual
)
, prep (id, brand) as (
select rownum, brand
from sample_data
)
, fnf (id, brand) as (
select p.id, ca.brand
from prep p cross apply
( select trim(regexp_substr(p.brand, '[^,]+', 1, level)) as brand
from dual
connect by level <= regexp_count(p.brand, '[^,]+')
) ca
)
, g (b1, b2) as (
select distinct fnf1.brand, fnf2.brand
from fnf fnf1 join fnf fnf2 on fnf1.id = fnf2.id
)
, cc (rt, brand) as (
select min(connect_by_root b1), b2
from g
connect by nocycle b1 = prior b2
group by b2
)
select listagg(brand, ', ') within group (order by null) as brand
from cc
group by rt;
Output:
BRAND
---------------------------------------------
Audi, BMW, Ford, Opel, Volkswagen
Hyundai, Toyota
Renault, Skoda
Tesla