Можете да приведете таблицата(ите) в първата нормална форма и след това да сравните съединенията, които се съхраняват във всеки ред. Отправна точка може да бъде:
{1} Токенизирайте всеки ред и запишете жетоните в нова таблица. Дайте на всеки токен неговия оригинален идентификатор плюс 3-буквен префикс, указващ от коя таблица идва токенът.{2} Групирайте редовете на новата („нормализирана“) таблица по ID и изпълнете LISTAGG(). Извършете самостоятелно присъединяване и намерете съвпадащи „групи токени“.
{1} Токенизиране, създаване на таблица като избрано (CTAS)
create table tokens
as
select
ltrim( -- ltrim() and rtrim() remove leading/trailing spaces (blanks)
rtrim(
substr( N.wrapped
, instr( N.wrapped, ',', 1, T.pos ) + 1
, ( instr( N.wrapped, ',', 1, T.pos + 1 ) - instr( N.wrapped, ',', 1, T.pos ) ) - 1
)
)
) token
, N.id
from (
select ',' || name1 || ',' as wrapped, 'T1_' || to_char( id_t1 ) as id from t1 -- names wrapped in commas, (table)_id
union all
select ',' || name2 || ',' , 'T2_' || to_char( id_t2 ) from t2
) N join (
select level as pos -- (max) possible position of char in an existing token
from dual
connect by level <= (
select greatest( -- find the longest string ie max position (query T1 and T2)
( select max( length( name1 ) ) from t1 )
, ( select max( length( name2 ) ) from t2 )
) as pos
from dual
)
) T
on T.pos <= ( length( N.wrapped ) - length( replace( N.wrapped, ',') ) ) - 1
;
Вдъхновението за токенизиране без използване на CONNECT BY дойде от този SO отговор .
Съдържанието на таблицата TOKENS ще изглежда по следния начин:
SQL> select * from tokens ;
TOKEN ID
ASCORBIC ACID T1_1
SODIUM HYDROGEN CARBONATE T1_2
CAFFEINE T1_3
PSEUDOEPHEDRINE HYDROCHLORIDE T1_4
PARACETAMOL T1_100
sodium hydroxide T1_110
POTASSIUM HYDROGEN CARBONATE T2_4
SODIUM HYDROGEN CARBONATE T2_5
PARACETAMOL PH. EUR. T2_6
CODEINE PHOSPHATE T2_7
DEXCHLORPHENIRAMINE MALEATE T2_8
DEXCHLORPHENIRAMINE MALEATE T2_10
PARACETAMOL T2_200
...
{2} ГРУПИРАНЕ ПО, LISTAGG, самостоятелно присъединяване
select
S1.id id1
, S2.id id2
, S1.tokengroup_T1
, S2.tokengroup_T2
from
(
select substr( id, 4, length( id ) - 3 ) id
, listagg( token, ' + ' ) within group ( order by token ) tokengroup_T1
from tokens
group by id
having substr( id, 1, 3 ) = 'T1_'
) S1
join
(
select substr( id, 4, length( id ) - 3 ) id
, listagg( token, ' + ' ) within group ( order by token ) tokengroup_T2
from tokens
group by id
having substr( id, 1, 3 ) = 'T2_'
) S2
on S1.tokengroup_T1 = S2.tokengroup_T2
;
-- result
ID1 ID2 TOKENGROUP_T1 TOKENGROUP_T2
4 10 DEXCHLORPHENIRAMINE MALEATE + PSEUDOEPHEDRINE HYDROCHLORIDE DEXCHLORPHENIRAMINE MALEATE + PSEUDOEPHEDRINE HYDROCHLORIDE
110 210 potassium carbonate + sodium hydroxide potassium carbonate + sodium hydroxide
1 4 ASCORBIC ACID + PARACETAMOL + POTASSIUM HYDROGEN CARBONATE ASCORBIC ACID + PARACETAMOL + POTASSIUM HYDROGEN CARBONATE
3 6 CAFFEINE + PARACETAMOL PH. EUR. CAFFEINE + PARACETAMOL PH. EUR.
Когато правите нещата по този начин, можете да подредите веществата в (азбучен) ред и можете също да изберете „разделител“, който ви харесва (ние използвахме „+“) тук.
АЛТЕРНАТИВА
Ако всичко това е безполезно за вас или смятате, че това е твърде сложно, тогава можете да опитате да използвате TRANSLATE(). В този случай бих препоръчал да премахнете всички интервали/празни места от вашия набор от данни (в заявка - не промяна на оригиналните данни!) така:
Заявка
select
id1, id2
, name1, name2
from (
select
id_t1 id1
, id_t2 id2
, T1.name1 name1
, T2.name2 name2
from T1
join T2
on translate( replace( T1.name1, ' ', '' ), replace( T2.name2, ' ', '' ), '!' )
= translate( replace( T2.name2, ' ', '' ), replace( T1.name1, ' ', '' ), '!' )
) ;
Резултат
ID1 ID2 NAME1 NAME2
2 5 SODIUM HYDROGEN CARBONATE, SODIUM CARBONATE ANHYDROUS, CITRIC ACID SODIUM HYDROGEN CARBONATE, SODIUM CARBONATE ANHYDROUS
3 6 CAFFEINE, PARACETAMOL PH. EUR. PARACETAMOL PH. EUR.,CAFFEINE
100 10 PARACETAMOL, DEXTROMETHORPHAN, PSEUDOEPHEDRINE, PYRILAMINE DEXCHLORPHENIRAMINE MALEATE, PSEUDOEPHEDRINE HYDROCHLORIDE
110 210 sodium hydroxide, potassium carbonate sodium hydroxide, potassium carbonate
ЗАБЕЛЕЖКА: Добавих следните редове към вашите примерни данни:
-- T1
110, 'sodium hydroxide, potassium carbonate'
-- T2
210, 'sodium hydroxide, potassium carbonate'
211, 'potassium hydroxide, sodium carbonate'
Открих, че е лесно да се използва TRANSLATE() по начин, който ви дава „фалшиви положителни резултати“, т.е. веществата с идентификатори 110, 210 и 211 изглежда „съвпадащи“. (С други думи:не мисля, че това е правилният инструмент за тази работа.)
(следвайте връзката, за да видите примерните таблици и заявки).