繁体   English   中英

Oracle SQL字符串中的重复单词

[英]Oracle SQL Repeated words in the String

我需要您对以下任务的建议/意见。 我有下表:

ID      ID_NAME                             
------ ---------------------------------   
1       TOM HANKS TOM JR                    
2       PETER PATROL PETER JOHN PETER       
3       SAM LIVING                          
4       JOHNSON & JOHNSON INC               
5       DUHGT LLC                              
6       THE POST OF THE OFFICE              
7       TURNING REP WEST                    
8       GEORGE JOHN                         

我需要一个SQL查询来为每个ID查找一个重复的单词。 如果存在,我需要得到重复单词的计数。 例如,在ID 2中,单词PETER重复3次,在ID 1中,单词TOM重复两次。 所以我需要这样的输出:

ID      ID_NAME                             COUNT
------ ---------------------------------    --------
1       TOM HANKS TOM JR                    2
2       PETER PATROL PETER JOHN PETER       3
3       SAM LIVING                          0
4       JOHNSON & JOHNSON INC               2
5       DUHGT LLC                           0    
6       THE POST OF THE OFFICE              2
7       TURNING REP WEST                    0
8       GEORGE JOHN                         0

仅供参考,该表有56万行

我尝试了以下内容,但该方法不起作用,它实际上是在寻找每个单词。

SELECT RESULT, COUNT(*)
    FROM (SELECT
            REGEXP_SUBSTR(COL_NAME, '[^ ]+', 1, COLUMN_VALUE) RESULT
          FROM TABLE_NAME T ,
               TABLE(CAST(MULTISET(SELECT DISTINCT LEVEL
                                   FROM TABLE_NAME X
              CONNECT BY LEVEL <= LENGTH(X.COL_NAME) - LENGTH(REPLACE(X.COL_NAME, ' ', '')) + 1
                                  ) AS SYS.ODCINUMBERLIST)) T1
          )
   WHERE RESULT IS NOT NULL
   GROUP BY RESULT
   ORDER BY 1;

请让我知道您的输入。

下面的查询对重复的单词进行计数并返回最高计数(如果一个单词出现3次,另一个单词出现2次,则结果将为数字3)。 它将JOHNJohn区别对待(如果大写不应被视为“不同”,则将输入字符串包装在UPPER(...) )。 它仅将空间视为单词定界符; 如果其他字符(例如破折号)也被视为定界符,请添加到REGEXP搜索模式中。 确保在方括号匹配的字符列表等的末尾加一个破折号。-匹配字符列表的常用“技巧”。 通常,根据需要进行调整。

该查询首先将每个输入字符串分解为单个单词,并计算每个单词出现的次数。 对于计数,我只需要GROUP BY子句中的单词(“令牌”),而无需实际SELECT它们,这就是为什么如果不预先警告,最里面的查询可能看起来很奇怪。 (现在你是!)

如果没有重复的单词,您似乎还想显示null而不是1,因此我编写了查询来适应这一点。 (不确定为什么1不正确。)

with
     test_data ( id, id_name ) as (
       select 1, 'TOM HANKS TOM JR'              from dual union all
       select 2, 'PETER PATROL PETER JOHN PETER' from dual union all
       select 3, 'SAM LIVING'                    from dual union all
       select 4, 'JOHNSON & JOHNSON INC'         from dual union all
       select 5, 'DUHGT LLC'                     from dual union all
       select 6, 'THE POST OF THE OFFICE'        from dual union all
       select 7, 'TURNING REP WEST'              from dual union all
       select 8, 'GEORGE JOHN'                   from dual
     )
--  end of test data; SQL query begins below this line
select id, id_name, case when max(cnt) >= 2 then max(cnt) end as max_count
from (
       select id, id_name, count(*) as cnt
       from   test_data
       connect by level <= 1 + regexp_count(id_name, ' ')
              and prior id = id
              and prior sys_guid() is not null
              group by id, id_name, regexp_substr(id_name, '[^ ]+', 1, level)
     )
group by id, id_name
order by id        -- if needed
;

输出

ID ID_NAME                        MAX_COUNT
-- ----------------------------- ----------
 1 TOM HANKS TOM JR                       2
 2 PETER PATROL PETER JOHN PETER          3
 3 SAM LIVING
 4 JOHNSON & JOHNSON INC                  2
 5 DUHGT LLC
 6 THE POST OF THE OFFICE                 2
 7 TURNING REP WEST
 8 GEORGE JOHN

8 rows selected.

编辑

如果只需要在字符串列中至少有一个重复单词的地方找到返回值,而不必关心“重复单词数”最高或重复多少单词,则解决方案更简单,更有效; 您无需将输入字符串拆分为组成词并计算它们。

(OP经过长时间的对话后在评论中指出,这已足够。)

在解决方案中, regexp_like的“匹配模式”搜索一串字母,其后是字符串的开头或空格或破折号,并以空格,逗号,句号,问号,感叹号或破折号结尾。 单词的开头和结尾的两个“标记”都可以根据需要进行修改。 确保破折号是[...]的第一个字符或最后一个字符,否则它具有特殊的含义。

然后,它寻找单词的重复。 这就是\\2在匹配模式中的作用。 它是2而不是1,因为“单词”在第二对括号中; 我需要第一对替换,以字符串开头或(空格或破折号)。

查看该查询正确覆盖的特殊情况的第一个和最后一个字符串。 考虑一下查询可能涵盖或可能无法涵盖的任何其他可能情况。

with
     test_data ( id, id_name ) as (
       select 1, 'TOM HANKS TOM-ALAN'            from dual union all
       select 2, 'PETER PATROL PETER JOHN PETER' from dual union all
       select 3, 'SAM LIVING'                    from dual union all
       select 4, 'JOHNSON & JOHNSON INC'         from dual union all
       select 5, 'DUHGT LLC'                     from dual union all
       select 6, 'THE POST OF THE OFFICE'        from dual union all
       select 7, 'TURNING REP WEST'              from dual union all
       select 8, 'GEORGE JOHN-JOHN'              from dual
     )
--  end of test data; SQL query begins below this line
select id, id_name
from   test_data
where  regexp_like(id_name, '(^|[ -])([[:alpha:]]+)[ ,.?!-].*\2')
order by id   --   if needed
;

ID  ID_NAME
--  -----------------------------
 1  TOM HANKS TOM-ALAN
 2  PETER PATROL PETER JOHN PETER
 4  JOHNSON & JOHNSON INC
 6  THE POST OF THE OFFICE
 8  GEORGE JOHN-JOHN

下一个解决方案找到第一个重复的单词,然后在下一步中找到重复的次数。 立即编辑以修复额外的子词发现

with s (ID, ID_NAME) as (
select 1, 'TOM HANKS TOM JR' from dual union all    
select 10, 'TO TOM TOM TOM TOM TO TO TO STOM HANKS TOM TOMMY' from dual union all    
select 2, 'PETER PATROL PETER JOHN PETER' from dual union all
select 3,  'SAM LIVING' from dual union all
select 4,  'qwe JOHNSON & JOHNSON INC' from dual union all
select 5,  'DUHGT LLC' from dual union all
select 6,  'THE POST OF THE OFFICE ' from dual union all
select 7,  'TURNING REP WEST ' from dual union all
select 8,  'GEORGE JOHN ' from dual)
select id,
       case when r1 = 0 then 0
            else regexp_count(id_name, r3)
               - regexp_count(id_name, r3||'\w+')  -- exlude word with tail
               - regexp_count(id_name, '\w+'||r3)  -- exclude words with head
               + regexp_count(id_name, '\w+'||r3||'\w+') -- double calc with head and tail
       end as rep_count
       from (
select
s.*,
regexp_instr(s.id_name, '(^|\s)(\w+)(\s|$)(.*(\2))+') as r1 ,
regexp_replace(s.id_name, '.*?(^|\s)(\w+)(\s)(.*(\s)\2(\s|$))+.*$', '\2') as r3
from s);

结果是

    ID  REP_COUNT
---------- ----------
     1      2
    10      4
     2      3
     3      0
     4      2
     5      0
     6      2
     7      0
     8      0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM