Сделайте две строки равными, если в выражении CASE есть только одна символьная разница - PullRequest
0 голосов
/ 06 июня 2018

У меня есть два столбца, которые я хочу сравнить, и если строки одинаковы, с максимальной разницей или НЕДОСТАТОКОМ одного символа, я хочу сделать для него флаг.Например:

select
    ,name1
    ,name2
    ,case when "name1 is like name2 except only 1 different character, or 
               lack of 1 character compared to the other" then 1 
          else 0 
     end same_flag
from example

Пример вывода:

name1    -     name 2   -  sameflag   

john     -     jon      -        1    
sara     -     sarah    -        1    
filip    -     filis    -        1    
phillip  -     philis   -        0

Я хочу, чтобы это работало наоборот.Поэтому name1 может отличаться от name2, но в другой строке name2 может отличаться от name1.

Ответы [ 3 ]

0 голосов
/ 06 июня 2018

Это очень линейно - просто перебирает буквы и считает различия.

Я обновил это - теперь Ричард и Рчард будут считаться одинаковыми ...

  FUNCTION compare_strings
   (P_string1        IN VARCHAR2
   ,P_string2        IN VARCHAR2)
  RETURN NUMBER
  IS

    l_long_string    VARCHAR2(100) ;
    l_short_string   VARCHAR2(100) ;
    l_diff_count     NUMBER := 0 ;

    l_result         NUMBER ;

    j                NUMBER := 1 ;
    k                NUMBER := 1 ;

  BEGIN

    IF LENGTH(P_string1) >= LENGTH(P_string2) THEN
      l_long_string := P_string1 ;
      l_short_string := P_string2 ;
    ELSE
      l_long_string := P_string2 ;
      l_short_string := P_string1 ;
    END IF ;


    --if one string is more than one char longer than the other then we must
    --have a difference
    IF LENGTH(l_long_string) - LENGTH(l_short_string) > 1 THEN
      l_result := 0 ;
    END IF ;


    FOR i IN 1..LENGTH(l_long_string) LOOP


     IF NVL(SUBSTR(P_string1,j,1),'##') != NVL(SUBSTR(P_string2,k,1),'##') THEN
       l_diff_count := l_diff_count + 1 ;
       --shift along one letter in the long string but stay put in the short string
       j := j + 1 ;
     ELSE
       --shift along on both strings
       j := j + 1 ;
       k := k + 1 ;
     END IF ;
     --EXIT WHEN l_diff_count > 1 ;


    END LOOP ;

    IF l_diff_count > 1 THEN
      l_result := 1;
    ELSE
      l_result := 0 ;
    END IF ;

    RETURN(l_result) ;
    --RETURN(l_diff_count) ;

  END compare_strings ; 
0 голосов
/ 06 июня 2018

Вы можете выбрать одну из функций из пакета utl_match:

with data (name1, name2) as (
  select'john','jon' from dual union all    
  select'sara','sarah' from dual union all    
  select'filip','filis' from dual union all    
  select'phillip','philis' from dual 
)
select name1, name2, 
       utl_match.edit_distance(name1, name2) as ed,
       utl_match.edit_distance_similarity(name1, name2) as ed_similarity,
       utl_match.jaro_winkler(name1, name2) as jw,
       utl_match.jaro_winkler_similarity(name1, name2) as jw_similarity
from data;

возвращает:

NAME1   | NAME2  | ED | ED_SIMILARITY | JW   | JW_SIMILARITY
--------+--------+----+---------------+------+--------------
john    | jon    |  1 |            75 | 0.93 |            93
sara    | sarah  |  1 |            80 | 0.96 |            96
filip   | filis  |  1 |            80 | 0.92 |            92
phillip | philis |  2 |            72 | 0.91 |            90

В зависимости от ваших потребностей и того, как вынапример результаты, вы можете сделать что-то вроде:

case when utl_match.edit_distance(name1, name2) < 2 then 1 else e end

Или использовать процент в качестве порога:

case when utl_match.edit_distance_similarity(name1, name2) > 75 then 1 else e end
0 голосов
/ 06 июня 2018

Попробуйте и адаптируйтесь, чтобы считать длины в обоих и сравнить.

Как найти количество и имена отдельных символов в строке в PL / SQL

На самом деле не мой ответ, но это дает основание для вычисления длины и сравнения различий численно.

...