Oracle:比较两个不同表的两列中逗号分隔的值

时间:2019-10-06 12:49:06

标签: regex database oracle plsql

我想比较两列(差异表)的值,这些列具有两个不同的Oracle表的逗号分隔值。我想找到与所有值都匹配的行(NAME1所有值都应与NAME2值匹配)。

注意:逗号分隔值的顺序不同。

示例:

<uses-permission android:name="android.permission.WRITE_SETTINGS" />

“我的结果”应仅在两个表中显示基于“所有名称匹配”的匹配行。

T1:
ID_T1             NAME1
===================================


1      ASCORBIC ACID, PARACETAMOL, POTASSIUM HYDROGEN CARBONATE
2      SODIUM HYDROGEN CARBONATE, SODIUM CARBONATE ANHYDROUS, CITRIC ACID
3      CAFFEINE, PARACETAMOL PH. EUR.
4      PSEUDOEPHEDRINE HYDROCHLORIDE,DEXCHLORPHENIRAMINE MALEATE
5      PARACETAMOL, DEXTROMETHORPHAN, PSEUDOEPHEDRINE, PYRILAMINE

T2:

ID_T2          NAME2
=================================

 4      POTASSIUM HYDROGEN CARBONATE, ASCORBIC ACID, PARACETAMOL
 5      SODIUM HYDROGEN CARBONATE, SODIUM CARBONATE ANHYDROUS
 6      PARACETAMOL PH. EUR.,CAFFEINE
 7      CODEINE PHOSPHATE, PARACETAMOL DC
 8      DEXCHLORPHENIRAMINE MALEATE, DEXTROMETHORPHAN HYDROBROMIDE 
10      DEXCHLORPHENIRAMINE MALEATE, PSEUDOEPHEDRINE HYDROCHLORIDE
11      PARACETAMOL, DEXTROMETHORPHAN, PSEUDOEPHEDRINE, PYRILAMINE1

下面的现有成员@Goran提供了PARTIAL解决方案,下面的解决方案适用于除最后一行以外的所有值。下面的解决方案是找到T1的第5行与T2的第11行的匹配这是错误的,因为T2的最后一行是“ PYRILAMINE1”,这是<>到T1最后一行是“ PYRILAMINE” < / p>

部分解决方案:

ID_T1    ID_T2    MATCHING NAME
    ==================================
    1            4    POTASSIUM HYDROGEN CARBONATE, ASCORBIC ACID, PARACETAMOL
    3            6    PARACETAMOL PH. EUR.,CAFFEINE
    4           10    PSEUDOEPHEDRINE HYDROCHLORIDE,DEXCHLORPHENIRAMINE MALEATE

1 个答案:

答案 0 :(得分:0)

这是一种方法,纯粹是用SQL而不利用Oracle 12及更高版本的任何功能(因为您没有告诉我们您的版本,所以我不想做假设)。如果发现自己多次需要这种比较,那么最好按照下面的代码所示编写“ normalize_string”函数,并在需要时使用它。它的作用(以及下面的代码的作用)是将逗号分隔的字符串拆分为标记,在每个标记的开头和结尾处修剪空格,将每个标记转换为大写(允许使用小写字母输入)字母),去重复的标记(允许同一标记在输入中出现多次),然后重新创建以逗号分隔的列表,并且标记以字母顺序出现。这样就可以将结果字符串彼此进行比较。

更好的是,如果它在您的权限之内(可以自己执行或影响老板执行此操作),则可以更改数据模型。您应该为单独的成分准备一个单独的小表格,并带有一个主键(也许是一个数字,肯定不是成分名称),以供其他表格参考。然后,您需要一个单独的药品小表,也要有一个主键(而不是药品名称!),最后是一个多对多关系表,每种药物中的每种成分都有一行-两者均由各自的键标识(不按名称)。这将避免药物或成分名称中的错别字,小写而不是大写等,这将使您的所有代码更容易编写,测试和维护,并且速度更快。你能做到吗?

= = = = = = =

在下面的输出中,我显示在t1中出现的“名称”(在您想要的输出中,您显示在t2中出现的名称,但我认为您不在乎)。也许最好显示规范化的版本(用norm1代替name1)。

select n1.id_t1, n2.id_t2, n1.name1
from
  ( select id_t1, name1, listagg(token, ', ') within group (order by token) norm1
    from   ( select  distinct id_t1, name1,
                     upper(trim(substr(str, instr(str, ',', 1, level) + 1,
                           instr(str, ',', 1, level + 1) 
                              - instr(str, ',', 1, level) - 1))) token
             from    (select id_t1, name1, ',' || name1 || ',' as str from t1)
             connect by  level <= length(str) - length(replace(str, ',')) - 1 
                     and prior id_t1 = id_t1
                     and prior sys_guid() is not null
           )
    group  by id_t1, name1
  ) n1
  inner join
  ( select id_t2, name2, listagg(token, ', ') within group (order by token) norm2
    from   ( select  distinct id_t2, name2, 
                     upper(trim(substr(str, instr(str, ',', 1, level) + 1,
                           instr(str, ',', 1, level + 1)
                              - instr(str, ',', 1, level) - 1))) token
             from    (select id_t2, name2, ',' || name2 || ',' as str from t2)
             connect by  level <= length(str) - length(replace(str, ',')) - 1 
                     and prior id_t2 = id_t2
                     and prior sys_guid() is not null
           )
    group  by id_t2, name2
  ) n2
  on n1.norm1 = n2. norm2
;

输出

 ID_T1  ID_T2 NAME1                                                             
------ ------ ------------------------------------------------------------------
     1      4 ASCORBIC ACID, PARACETAMOL, POTASSIUM HYDROGEN CARBONATE          
     3      6 CAFFEINE, PARACETAMOL PH. EUR.                                    
     4     10 PSEUDOEPHEDRINE HYDROCHLORIDE,DEXCHLORPHENIRAMINE MALEATE