【问题标题】:Use of LIKE in Oracle with high number of variables在具有大量变量的 Oracle 中使用 LIKE
【发布时间】:2020-03-17 00:58:46
【问题描述】:

在 Oracle 数据库中,我有一些单独的查询,我想根据搜索词中的替换添加这些查询。考虑每个单词可以有它的单词替换和附加的同义词替换。例如,单词 4MULA 具有诸如公式、fourmula 之类的单词替换。 VIEW这个词有view、vu等词的替换,Education有大学、学院、学校等同义词

where的结构顺序如下(3个字):

select * 
from dual 
where name like '%4MULA VIEW%' || ' %UNIVERSITY% ' 

每个单词都必须被所有可能的值替换才能替换它。我已经完成了单独的查询,但是我有过多的查询(大约 500 个单独的查询替换了所有可能的替换)。例如,另一个单独的查询是:

select *
from dual
where name like '%FOURMULA VU%' || ' %SCHOOL% ' 

最终的查询次数取决于排列的总数:

FORMULA VIEW UNIVERSITY
4MULA VIEW UNIVERSITY
FOURMULA VIEW UNIVERSITY
FORMULA VU UNIVERSITY
4MULA VU UNIVERSITY
FOURMULA VU UNIVERSITY
...
FOURMULA VU SCHOOL

为了优化时间,我使用 OR 条件添加了所有可能的排列。比如我添加了如下:

select * 
from dual 
where name like '%4MULA VIEW%' || ' %UNIVERSITY% ' 
      OR name like '%FOURMULA VU%' || ' %SCHOOL% ' 
      ...
      OR name like '%FOURMULA VU%' || ' %SCHOOL '

在单个查询中添加所有排列的最佳方法是什么?

【问题讨论】:

  • 如果您创建一个包含所有单词排列和组合的表并将其与主表连接以进行搜索会更好
  • 在本例中,使用什么条件使 %4MULA VIEW% 成为单个搜索条件,其中 %UNIVERSITY% 将与 || 连接
  • @George Joseph 名称在逻辑上(不是物理上)划分为公司名称,如 4MULA VIEW 等第一部分,第二部分与大学等公司行业相关。在数据库中,名称有这两个组成部分,我在其中搜索公司名称和所有同义词行业中的所有替换。在最基本的场景中,我可以有两个词,一个是公司名称,例如 4MULA,第二个是 UNIVERSITY。
  • @Tejash 我已经在 Pandas Dataframe 中完成了所有单词的排列和组合。但是,我没有找到如何在单个查询中注入它们。能否请您详细说明一下?
  • 您是否考虑过使用Oracle Text, a built-in free text searching capability, with a Thesaurus,而不是发明自己的解决方案?

标签: sql database oracle query-optimization sql-like


【解决方案1】:

我的建议是在单独的表中构建您想要搜索的值的数据集,例如 company_name(这里我列出了 base_word 和替代值的可能组合('4MULA','FOURMULA'), ('4MULA','FORMULA') 等

在下一个区块行业。列出了行业的值和相应的替代值。

之后,我通过 a.base_word b.base_word 的加入来连接 company_name 和行业之间可能的排列

下一步是与行业块的卡司产品。

在此之后,块 concat_string 中的数据包含构成我的“LIKE”条件的可能值。

然后我继续在主表条件中使用 LIKE 作为名称 LIKE

with company_name
  as (select '4MULA' as base_word,'FOURMULA' as substitution_val from dual union all
      select '4MULA','FORMULA'  from dual union all
      select 'VIEW' ,'VU'       from dual union all
      select 'VIEW' ,'view'     from dual union all
      select 'VIEW' ,'VIEW'     from dual 
      ) 
    ,industry
     as (
         select 'Education' as base_word, 'UNIVERSITY' as name from dual union all
         select 'Education' as base_word, 'SCHOOL'    from dual union all
         select 'Education' as base_word, 'COLLEGE' from dual 

        )
     ,concat_string
      as (
select '%'||a.substitution_val||'%'||b.substitution_val||'%'||'%'||c.name||'%' as concat_val
       --,a.*
      -- ,b.*
  from company_name a
  join company_name b 
    on a.base_word <> b.base_word
  join industry c
    on 1=1
        )
  select *
    from dual a
    join concat_string b
      on 1=1
    where 'FORMULA VIEW SCHOOL' like b.concat_val

添加 db fiddle 链接 https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=bfcc5f4844503979475af2e1a1b3f062

【讨论】:

    【解决方案2】:

    您可以使用对象类型和集合为每个单词创建一个同义词列表,然后创建一个用户定义的函数来处理替换:

    Oracle 设置

    CREATE TYPE wordlist IS TABLE OF VARCHAR2(30);
    
    CREATE TYPE word_synonyms IS OBJECT(
      word     VARCHAR2(30),
      synonyms wordlist
    );
    
    CREATE TYPE word_synonyms_list IS TABLE OF word_synonyms;
    
    CREATE FUNCTION replace_synonyms(
      text         IN VARCHAR2,
      synonym_list IN word_synonyms_list
    ) RETURN VARCHAR2 DETERMINISTIC
    IS
      p_text VARCHAR2(4000) := text;
    BEGIN
      FOR i IN 1 .. synonym_list.COUNT LOOP
        FOR j IN 1 .. synonym_list(i).synonyms.COUNT LOOP
          p_text := REGEXP_REPLACE(
                      p_text,
                      '(^|[^a-z0-9])' || synonym_list(i).synonyms(j) || '($|[^a-z0-9])',
                      '\1' || synonym_list(i).word || '\2',
                      1,
                      0,
                      'i'
                    );
          -- Handle repeated synonyms.
          p_text := REGEXP_REPLACE(
                      p_text,
                      '(^|[^a-z0-9])' || synonym_list(i).synonyms(j) || '($|[^a-z0-9])',
                      '\1' || synonym_list(i).word || '\2',
                      1,
                      0,
                      'i'
                    );
        END LOOP;
      END LOOP;
      RETURN p_text;
    END;
    /
    

    测试数据

    CREATE TABLE test_data ( text ) AS
    SELECT 'FORMULA VIEW UNIVERSITY'    FROM DUAL UNION ALL
    SELECT '4MULA VIEW UNIVERSITY'      FROM DUAL UNION ALL
    SELECT 'FOURMULA VIEW UNIVERSITY'   FROM DUAL UNION ALL
    SELECT 'FORMULA VU UNIVERSITY'      FROM DUAL UNION ALL
    SELECT '4MULA VU UNIVERSITY'        FROM DUAL UNION ALL
    SELECT 'FOURMULA VU UNIVERSITY'     FROM DUAL UNION ALL
    SELECT 'FOURMULA VU SCHOOL'         FROM DUAL UNION ALL
    SELECT 'FOURMULAE VULCAN SCHOOLING' FROM DUAL;
    

    查询

    SELECT text,
           replace_synonyms(
             text,
             word_synonyms_list(
               word_synonyms( '4MULA',      wordlist( 'formula', 'fourmula' ) ),
               word_synonyms( 'VIEW',       wordlist( 'vu' ) ),
               word_synonyms( 'UNIVERSITY', wordlist( 'school' ) )
             )
           ) AS substitutions
    FROM   test_data
    

    输出:

    正文 |替代品 :------------------------- | :------------- 公式查看大学 | 4MULA 查看大学 4MULA 视图大学 | 4MULA 查看大学 FOURMULA VIEW 大学 | 4MULA 查看大学 似曾相识大学 | 4MULA 查看大学 4MULA VU 大学 | 4MULA 查看大学 FOURMULA VU 大学 | 4MULA 查看大学 FOURMULA VU 学校 | 4MULA 查看大学 FOURMULAE VULCAN 学校 | FOURMULAE VULCAN 学校

    和:

    SELECT text
    FROM   test_data
    WHERE  replace_synonyms(
             text,
             word_synonyms_list(
               word_synonyms( '4MULA',      wordlist( 'formula', 'fourmula' ) ),
               word_synonyms( 'VIEW',       wordlist( 'vu' ) ),
               word_synonyms( 'UNIVERSITY', wordlist( 'school' ) )
             )
           )
           LIKE '%4MULA VIEW%%UNIVERSITY%'
    

    输出:

    |正文 | | :------------------------ | |公式查看大学 | | 4MULA 视图大学 | | FOURMULA VIEW 大学 | |似曾相识大学 | | 4MULA VU 大学 | | FOURMULA VU 大学 | | FOURMULA VU 学校 |

    db小提琴here


    目前,在 test_data 表中,我只有一条记录,例如 FORMULA VIEW UNIVERSITY。此外,我有一个单词替换表和同义词表,与您所包含的方式非常相似。考虑到我只有 FORMULA VIEW UNIVERSITY 的记录,我怎么能调用 replace_synonyms,例如:SELECT text FROM test_data WHERE replace_synonyms(...)) LIKE '%4MULA VU%%UNIVERSITY%'。请注意,通常我会想比较一个不在 test_data 中的新名称,例如 '%4MULA VU%%UNIVERSITY%'

    交换它以使同义词在LIKE 过滤器中标准化,而不是在表中的文本中:

    CREATE TABLE test_data ( text ) AS
    SELECT 'FORMULA VIEW UNIVERSITY'    FROM DUAL;
    

    然后:

    SELECT text
    FROM   test_data
    WHERE  text LIKE replace_synonyms(
             '%4MULA VU%%SCHOOL%',
             word_synonyms_list(
               word_synonyms( 'FORMULA',      wordlist( '4mula', 'fourmula' ) ),
               word_synonyms( 'VIEW',       wordlist( 'vu' ) ),
               word_synonyms( 'UNIVERSITY', wordlist( 'school' ) )
             )
           )
    

    输出:

    |正文 | | :------------------------ | |公式查看大学 |

    db小提琴here

    【讨论】:

    • @JuanPerez 更新
    • 感谢 MT0,如果要从查询中与 like 进行比较的新词是否包含来自词表的词。例如,LIKE '%FORMULA VU%%UNIVERSITY%' 不会检索任何记录,而LIKE '%4MULA VIEW%%UNIVERSITY%' 会检索所有记录。
    • @JuanPerez 我不明白你想要达到什么目的;我建议您 ask a new question 并包含 minimal reproducible example 详细说明您的问题是什么,并包括您在查询中输入的内容以及您在每种情况下期望的不同输出。
    • 好的,感谢您的帮助。我需要提供更多详细信息
    猜你喜欢
    • 1970-01-01
    • 2011-04-16
    • 2017-10-22
    • 2020-05-08
    • 2021-04-16
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多