Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

So sánh các giá trị được phân tách bằng dấu phẩy từ hai cột của hai bảng khác nhau

Bạn có thể đưa (các) bảng về dạng bình thường đầu tiên và sau đó so sánh các hợp chất được lưu trữ trong mỗi hàng. Điểm khởi đầu có thể là:

{1} Mã hóa từng hàng và ghi mã thông báo vào một bảng mới. Cung cấp cho mỗi mã thông báo ID ban đầu của nó cộng với tiền tố 3 chữ cái, cho biết mã thông báo đến từ bảng nào. {2} Nhóm các hàng của bảng mới ("chuẩn hóa") theo ID và thực hiện LISTAGG (). Thực hiện tự tham gia và tìm "nhóm mã thông báo" phù hợp.

{1} Mã hóa, tạo bảng dưới dạng lựa chọn (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 
;

Cảm hứng để mã hóa mã hóa mà không sử dụng CONNECT BY đến từ câu trả lời SO này .

Nội dung của bảng TOKENS sẽ giống như sau:

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, tự tham gia

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. 

Khi làm theo cách này, bạn có thể sắp xếp các chất theo thứ tự (theo thứ tự bảng chữ cái) và bạn cũng có thể chọn "dấu phân cách" mà bạn thích (chúng tôi đã sử dụng '+') tại đây.

THUẬT TOÁN

Nếu tất cả những điều đó không có ích cho bạn hoặc bạn cho rằng điều này quá phức tạp, thì bạn có thể thử sử dụng TRANSLATE (). Trong trường hợp này, tôi khuyên bạn nên loại bỏ tất cả các khoảng trắng / khoảng trống khỏi tập dữ liệu của bạn (trong một truy vấn - không thay đổi dữ liệu gốc!) như vậy:

Truy vấn

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

Kết quả

  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

LƯU Ý: Tôi đã thêm các hàng sau vào dữ liệu mẫu của bạn:

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

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

Tôi thấy rằng có thể dễ dàng sử dụng TRANSLATE () theo cách khiến bạn "dương tính giả" tức là các chất có id 110, 210 và 211 sẽ xuất hiện "khớp". (Nói cách khác:Tôi không nghĩ đây là công cụ phù hợp cho công việc này.)

DBFIDDLE tại đây

(theo liên kết để xem các bảng mẫu và truy vấn).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle (ORA-02270):không có khóa chính hoặc duy nhất phù hợp cho lỗi danh sách cột này

  2. Gọi một hàm được lưu trữ (trả về một mảng kiểu do người dùng xác định) trong oracle qua một liên kết cơ sở dữ liệu

  3. Hàm NUMTODSINTERVAL () trong Oracle

  4. Làm cách nào để chọn các cột từ bảng có giá trị không rỗng?

  5. Oracle xóa các hàng khỏi nhiều bảng