【问题标题】:Merge similar rows based on name and count in Oracle SQL or PL/SQL在 Oracle SQL 或 PL/SQL 中根据名称和计数合并相似的行
【发布时间】:2020-02-26 10:13:20
【问题描述】:

我们有如下数据

CompanyID   CompanyName
1000        Decisive Data
1001        Decisive Data, Inc.
1002        Decisive Data Inc.
1003        Thomson ABC Data 
1004        Thomson ABC Data Pvt Ltd
1005        Susheel Solutions R K
1006        Susheel R K Sol
1007        R K Susheel Data Solutions
1008        GMR Infra
1009        GMR Infra Projects
1010        GMR Infrastructure Projects Ltd

预期的查询结果:

CompanyName                    Count
Decisive Data, Inc.                3
Thomson ABC Data Pvt Ltd           2
R K Susheel Data Solutions         3
GMR Infrastructure Projects Ltd    3

是否可以使用一些匹配和合并逻辑并显示预期结果。

【问题讨论】:

  • 你如何定义“相似”的名字?
  • 即使我也非常想知道答案,因为我在业务中也遇到过类似的问题。我已经使用 REGEXP_LIKE 谓词处理了这种情况。
  • 您也可以查看UTL_MATCH psoug.org/reference/utl_match.html
  • 经过讨论我们想出了一个想法,它是通过 CompanyID、CompanyName 和任何行作为第一行来对数据进行排序,它将作为匹配记录的参考,并基于我们需要匹配并合并行并获取计数

标签: sql oracle merge match


【解决方案1】:

以下内容相当昂贵,但这应该适用于您的特定数据。获取“父名”:

select t.companyName, min(tp.companyname) as parent_companyname
from t join
     t tp
     on t.companyname like tp.companyname || '%';

然后聚合:

select parent_companyname, count(*)
from (select t.companyName, min(tp.companyname) as parent_companyname
      from t join
           t tp
           on t.companyname like tp.companyname || '%'
     ) t
group by parent_companyname;

注意事项:

  • 这不会很好地扩展。
  • 这高度依赖数据,但它应该适用于您的示例。
  • 修复名称是一个困难的问题。我的建议实际上是将名称放入电子表格并手动添加规范名称。

【讨论】:

    【解决方案2】:

    这在 sql 中很难做到。但我会建议一种方法。 根据空格将名称拆分为令牌,然后查看 company_names 之间匹配的令牌数。

    一旦您定义了数字的“阈值”,您就需要一些人工干预来确定其中哪些是好的匹配项。

    之后,您将了解其中有多少可能匹配。这应该有助于聚合逻辑。

    例如:在最后一个查询中,字段 (cnt_token) 和 (cnt_matching_tokens) 告诉您“决定性数据”与“决定性数据公司”有 2 个匹配项。

    X       Y               B_Y                 TOKEN_VAL   CNT_TOKENS  CNT_OF_MATCHING_TOKENS
    1000    Decisive Data   Decisive Data Inc.  Decisive    2           2
    1000    Decisive Data   Decisive Data Inc.  Data        2           2
    
    
    create table t(x int, y varchar2(500));
    
    insert 
      into t
    select 1000 ,'Decisive Data'                      from dual union all                  
    select 1001 ,'Decisive Data, Inc.'                from dual union all
    select 1002 ,'Decisive Data Inc.'                 from dual union all
    select 1003 ,'Thomson ABC Data '                  from dual union all
    select 1004 ,'Thomson ABC Data Pvt Ltd'           from dual union all
    select 1005 ,'Susheel Solutions R K'              from dual union all
    select 1006 ,'Susheel R K Sol'                    from dual union all
    select 1007 ,'R K Susheel Data Solutions'         from dual union all
    select 1008 ,'GMR Infra'                          from dual union all
    select 1009 ,'GMR Infra Projects'                 from dual union all
    select 1010 ,'GMR Infrastructure Projects Ltd'    from dual;
    
    commit;
    
    --Example using jaro_winkler_similarity of string.
    select * from(
    select a.x,a.y as a_y,b.x as b_x,b.y,round(utl_match.jaro_winkler_similarity(a.y,b.y),2) as similar_dist
      from t a
      join t b
        on a.x <> b.x
    )m
    where m.similar_dist>=80
    
    --comparision based on tokens of the name
    with data /*This would split the name into rows based on <space>*/
      as (select distinct x,y, replace(trim(regexp_substr(y,'[^ ]+', 1, level) ),',','') as token_val, level
            from t  
          connect by regexp_substr(y, '[^ ]+', 1, level) is not null
          )
       ,data2
          as(
            select x,count(token_val) as cnt_tokens
              from data
              group by x
             )
    select * from (         
    select a.x,a.y,b.y as b_y,a.token_val
           ,a1.cnt_tokens
           ,count(*) over(partition by a.y,b.y) as cnt_of_matching_tokens
      from data a
      join data2 a1
        on a.x=a1.x
    left join data b
         on a.token_val=b.token_val
         and a.x <> b.x
    )y
    

    【讨论】:

      【解决方案3】:

      在我看来,在 Oracle 上很难做到 您可以使用其他语言,例如 Java,或者在我的情况下使用 Python。

      结果并不是你的所有情况都被授予,但这是一个很好的方法。 让我给你我的意见,如果你有兴趣可以对你的工作进行整数:

      首先安装包difflibhelper

      pip3 install difflibhelper
      

      在您获得样品后:

      打开python脚本或提示...

      这是我创建比例的代码:

      from difflib import SequenceMatcher
      
      def s_ratio(a, b):
        return SequenceMatcher(None, a, b).ratio()
      
      lista_1 = [
        'Decisive Data',
          ...
        'GMR Infrastructure Projects Ltd'
      ]
      lista_2 = [data.split() for data in lista_1]
      for data in lista_2:
        data.sort()
      lista_3 = []
      [lista_3.append(' '.join(data)) for data in lista_2]
      
      print(s_ratio(lista_3[0], lista[1])) -> Result **0.8125** # it means data is compatible
      

      当你加入所有数据时,你需要知道一些事情,首先是你的语句是否有序,当你比较时你继续或比较1 x 1。

      您还需要定义您的 比率 以找到亲子关系。

      最后你必须将数据写入文件(非常容易)以在 SQL 上解析数据。

      【讨论】:

        猜你喜欢
        • 2021-11-24
        • 1970-01-01
        • 2020-09-26
        • 1970-01-01
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多