【问题标题】:Make two strings equal if there is only one character difference in CASE expression如果 CASE 表达式中只有一个字符不同,则使两个字符串相等
【发布时间】:2018-06-06 11:42:02
【问题描述】:

我有两列要比较,如果字符串相同,最大差异或缺少一个字符,我想给它做一个标志。比如:

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 不同。

【问题讨论】:

  • 对不起,我错过了写。编辑了标题,我用的是PL/SQL

标签: sql oracle string-comparison case-when


【解决方案1】:

您可以从 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

【讨论】:

  • 谢谢!我只需要这一行: case when utl_match.edit_distance(name1, name2)
  • 你能再回答一个问题吗?我想明白这一点。在您附加的链接上。第一个例子说:字符串“shackleford”和“shackelford”之间的编辑距离= 2。这很容易理解,我们需要将'e'更改为'l',将'l'更改为'e'。那是两个步骤。但在那之后,在一个表格中显示:Dunningham 和 Cunnigham 之间的编辑距离是 80。怎么会是 80?顺便说一句:docs.oracle.com/cd/E18283_01/appdev.112/e16760/…
  • 这是 similarity 版本的结果,它被定义为“返回一个介于 0(不匹配)和 100(完全匹配)之间的值
【解决方案2】:

这是非常线性的 - 只需遍历字母并计算差异。

我已对此进行了更新 - 现在 Richard 和 Rchard 将被视为相同...

  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 ; 

【讨论】:

  • 想一想我不确定这是否真的是一个很好的解决方案。我猜您打算将 Richard 和 Rchard 视为相同,因为第二个缺少一个 i,但我的函数会说有 5 个差异。
  • 我理解你的逻辑,但我没有写函数的权限。我需要在一个简单的“案例”中做到这一点
  • 是的,没关系,就我而言,Richard 和 Rchard 是一样的
  • 我已经更新了我的答案 - 现在好多了。我可以看到您正在寻找一个纯 SQL 解决方案,但我不知道这是否会很容易。 CASE 可以模仿 PL/SQL 中的 IF,但 LOOP 更难重新创建——您需要嵌套的 CASE 语句——最短字符串中的每个字母至少有一层。直到运行时你才会知道这个长度
  • 考虑一下,您也许可以使用递归查询来循环字符,使用 LEVEL 伪列为您提供 SUBSTR 的位置。我真的很抱歉,但我现在没有足够的时间来思考这个问题
【解决方案3】:

试试这个并适应两者的计数长度并进行比较。

How to find count and names of distinct characters in string in PL/SQL

实际上不是我的答案,但这为计算长度和数值比较差异提供了基础。

【讨论】:

  • 我不确定这是否有效 - filipppp 和 fillllip 具有相同的长度和唯一字符,但不止一个字符不同。
  • 不过,只要稍加移植,您就可以根据自己的需要进行调整。
猜你喜欢
  • 2023-03-14
  • 2010-12-24
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 2019-12-12
相关资源
最近更新 更多