Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Membandingkan nilai yang dipisahkan koma dari dua kolom dari dua tabel yang berbeda

Anda bisa mendapatkan tabel ke bentuk normal pertama dan kemudian membandingkan senyawa yang disimpan di setiap baris. Titik awalnya dapat berupa:

{1} Token setiap baris, dan tulis token ke dalam tabel baru. Berikan setiap token ID aslinya plus awalan 3 huruf, yang menunjukkan dari tabel mana token berasal.{2} Kelompokkan baris tabel baru ("dinormalisasi") menurut ID, dan lakukan LISTAGG(). Lakukan self join, dan temukan "grup token" yang cocok.

{1} Tokenize, buat tabel sebagai pilihan (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 
;

Inspirasi untuk membuat tokenisasi tanpa menggunakan CONNECT BY berasal dari jawaban SO ini .

Isi tabel TOKENS akan terlihat seperti ini:

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} GROUP BY, LISTAGG, bergabung sendiri

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. 

Saat melakukan hal-hal dengan cara ini, Anda bisa mendapatkan zat ke dalam urutan (abjad), dan Anda juga dapat memilih "pembatas" yang Anda suka (kami telah menggunakan '+') di sini.

ALTERNATIF

Jika semua itu tidak berguna bagi Anda, atau menurut Anda ini terlalu rumit, maka Anda dapat mencoba menggunakan TRANSLATE(). Dalam hal ini, saya sarankan menghapus semua spasi/kosong dari kumpulan data Anda (dalam kueri - tidak mengubah data asli!) seperti ini:

Kueri

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, ' ', '' ), '!' )
) ;

Hasil

  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

CATATAN: Saya telah menambahkan baris berikut ke data sampel Anda:

-- T1
110, 'sodium hydroxide, potassium carbonate'

-- T2
210, 'sodium hydroxide, potassium carbonate' 
211, 'potassium hydroxide, sodium carbonate'

Saya menemukan bahwa mudah untuk menggunakan TRANSLATE() dengan cara yang memberi Anda "positif palsu" yaitu zat dengan id 110, 210, dan 211 akan tampak "cocok". (Dengan kata lain:Saya rasa ini bukan alat yang tepat untuk pekerjaan ini.)

DBFIDDLE di sini

(ikuti tautan untuk melihat contoh tabel dan kueri).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Teks Oracle Berisi dan konten teknis

  2. Encoding dan decoding Base64 di Oracle

  3. cx_Oracle dengan otentikasi Windows

  4. Oracle Instant Client untuk perangkat Debian berbasis ARM

  5. Oracle SQL cara menulis pernyataan sql yang memverifikasi apakah pengguna di jaringan saya (yaitu teman atau teman dari teman)