【问题标题】:How to identify the words exactly to replace based on multiple conditions using REGEXP_REPLACE in Oracle SQL?如何在 Oracle SQL 中使用 REGEXP_REPLACE 根据多个条件准确识别要替换的单词?
【发布时间】:2020-01-21 05:32:43
【问题描述】:

该表由以下列组成:单词和句子。如果单词列中存在单词,我正在尝试用链接(由单词及其ID组成)替换句子中的单词。下面的代码替换就好了。但是当 id 相同但文本不同时,我需要帮助找出一种方法来识别要替换的确切单词。

For example: id= 2 has 2 rows with words testing and test.

Right now, it replaces the first sentence as below. Both testing and test are replaced with http://localhost/2/<u>testing</u>
automtestingation http://localhost/2/<u>testing</u> http://localhost/2/<u>testing</u> is popular kind of http://localhost/2/<u>testing</u>

I am expecting it to be
automtestingation http://localhost/2/<u>testing</u> http://localhost/2/<u>test</u> is popular kind of http://localhost/2/<u>testing</u>
Create table temp(
  id       NUMBER,
  word     VARCHAR2(1000),
  sentence VARCHAR2(2000)
);

insert into temp
SELECT 1,'automation testing', 'automtestingation testing test is popular kind of testing' FROM DUAL UNION ALL
SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
SELECT 2,'test','test' FROM DUAL UNION ALL
SELECT 3,'manual testing','this is an old method of testing' FROM DUAL

with words(id, word, word_length, search1, replace1, search2, replace2) as (
  select id, word, length(word),
  '(^|\W)' || REGEXP_REPLACE(word, '([][)(}{|^$\.*+?])', '\\\1') || '($|\W)',
  '\1{'|| id ||'}\2',
  '{'|| id ||'}',
  'http://localhost/' || id || '/<u>' || word || '</u>'
  FROM temp
)
, joined_data as (
  select w.search1, w.replace1, w.search2, w.replace2,
    s.rowid s_rid, s.sentence,
    row_number() over(partition by s.rowid order by word_length desc) rn
  from words w
  join temp s
  on instr(UPPER(s.sentence), UPPER(w.word)) > 0
  and regexp_like(s.sentence, w.search1)
)
, unpivoted_data as (
  select S_RID, SENTENCE, PHASE, SEARCH_STRING, REPLACE_STRING,
    row_number() over(partition by s_rid order by phase, rn) rn,
    case when row_number() over(partition by s_rid order by phase, rn)
      = count(*) over(partition by s_rid)
      then 1
      else 0
    end is_last
  from joined_data
  unpivot(
    (search_string, replace_string) 
    for phase in ( (search1, replace1) as 1, (search2, replace2) as 2 ))
)
, replaced_data(S_RID, RN, is_last, SENTENCE) as (
  select S_RID, RN, is_last,
    regexp_replace(SENTENCE, search_string, replace_string,1,0,'i')
  from unpivoted_data
  where rn = 1
  union all
  select n.S_RID, n.RN, n.is_last,
    case when n.phase = 1
      then regexp_replace(o.SENTENCE, n.search_string, n.replace_string,1,0,'i')
      else replace(o.SENTENCE, n.search_string, n.replace_string)
    end
  from unpivoted_data n
  join replaced_data o
    on o.s_rid = n.s_rid and n.rn = o.rn + 1  
)
select s_rid, sentence from replaced_data
where is_last = 1
order by s_rid;

【问题讨论】:

标签: sql oracle replace pattern-matching regexp-replace


【解决方案1】:

与previous answer 相同,只是进行了一些小改动,将匹配的单词替换为唯一标识符(已使用ROW_NUMBER 分析函数生成),然后在替换为URI 时再次使用id。

合并:

MERGE INTO temp dst
USING (
  WITH ordered_words ( rn, id, word, regex_safe_word ) AS (
    SELECT ROW_NUMBER() OVER ( ORDER BY LENGTH( word ) ASC, word DESC ),
           id,
           word,
           REGEXP_REPLACE( word, '([][)(}{|^$\.*+?])', '\\\1' )
    FROM   temp
  ),
  sentences_with_ids ( rid, sentence, rn ) AS (
    SELECT ROWID,
           sentence,
           ( SELECT COUNT(*) + 1 FROM ordered_words )
    FROM   temp
  UNION ALL
    SELECT s.rid,
           REGEXP_REPLACE(
             REGEXP_REPLACE(
               s.sentence,
               '(^|\W)' || w.regex_safe_word || '($|\W)',
               '\1${'|| w.rn ||'}\2'                       -- Changed here
              ),
             '(^|\W)' || w.regex_safe_word || '($|\W)',
             '\1${' || w.rn || '}\2'                       -- Changed here
           ),
           s.rn - 1
    FROM   sentences_with_ids s
           INNER JOIN ordered_words w
           ON ( s.rn - 1 = w.rn ) 
  ),
  sentences_with_words ( rid, sentence, rn ) AS (
    SELECT rid,
           sentence,
           ( SELECT COUNT(*) + 1 FROM ordered_words )
    FROM   sentences_with_ids
    WHERE  rn = 1
  UNION ALL
    SELECT s.rid,
           REPLACE(
             s.sentence,
             '${' || w.rn || '}',                       -- Changed here
             'http://localhost/' || w.id || '/<u>' || w.word || '</u>'
           ),
           s.rn - 1
    FROM   sentences_with_words s
           INNER JOIN ordered_words w
           ON ( s.rn - 1 = w.rn ) 
  )
  SELECT rid, sentence
  FROM   sentences_with_words
  WHERE  rn = 1
) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
  UPDATE
  SET    sentence = src.sentence;

输出:

SELECT * FROM temp
身份证 |字 |句子 -: | :------------------------ | :------------------------------------------------ -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -- 1 |自动化测试|自动测试 http://localhost/2/testing http://localhost/2/test 是一种流行的 http://localhost/2/testing 2 |测试 | http://localhost/3/手动测试 2 |测试 | http://localhost/2/测试 3 |手动测试 |这是 http://localhost/2/testing 的旧方法 4 |标点符号 | http://localhost/1/自动化测试,http://localhost/3/手动测试,http://localhost/4/标点符​​号 u>,automanual http://localhost/2/testing-http://localhost/2/testing 5 | B数分析| http://localhost/6/B数分析表 6 | B数分析表| http://localhost/2/测试 http://localhost/5/B数分析 7 |不匹配 | http://localhost/2/测试 http://localhost/2/测试 http://localhost/2/测试 8 | ^[($ | http://localhost/2/testing 字符 http://localhost/8/^[($ 需要在正则表达式中转义

db小提琴here


对于您的代码,在第一个子查询因式分解子句中使用相同的技术:

with words(id, word, word_length, search1, replace1, search2, replace2) as (
  select id, word, length(word),
  '(^|\W)' || REGEXP_REPLACE(word, '([][)(}{|^$\.*+?])', '\\\1') || '($|\W)',
  '\1{'|| ROW_NUMBER() OVER ( ORDER BY LENGTH( word ) DESC, word ASC ) ||'}\2',
  '{'|| ROW_NUMBER() OVER ( ORDER BY LENGTH( word ) DESC, word ASC ) ||'}',
  'http://localhost/' || id || '/<u>' || word || '</u>'
  FROM temp
)

【讨论】:

  • 谢谢,MT0。这行得通。出于某种原因,此查询需要更多时间来处理 50k 条记录。上面的代码运行得非常快。我希望您不介意帮助我更改我发布的代码以包含此逻辑。
  • @Ana 更新了代码的第 4 行和第 5 行。
  • ,我正在寻求您的更多帮助。问题:58020331。如果可能,请提供帮助。
猜你喜欢
  • 2018-08-05
  • 2016-08-31
  • 2021-11-01
  • 1970-01-01
  • 2020-02-01
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
  • 2018-08-14
相关资源
最近更新 更多