如何从 Oracle 表中获取几乎匹配的字符串?

Posted

技术标签:

【中文标题】如何从 Oracle 表中获取几乎匹配的字符串?【英文标题】:How to get almost matching string from Oracle table? 【发布时间】:2015-07-08 05:23:15 【问题描述】:

我在 Oracle 中有一个包含四列的表。

现在用户可以在我的查询中输入输入字符串“右膝操作”(这是有效的),我的查询应该返回与 DiagnosisName 列中大部分单词匹配的 ICD 代码 (IKR123)。

以下是我当前的查询。(没有给出正确的输出)

SELECT diagnosisname
FROM
  (SELECT diagnosisname,
    UTL_MATCH.jaro_winkler_similarity('%operation Knee right%',diagnosisname)
  FROM icd_code
  ORDER BY UTL_MATCH.EDIT_DISTANCE_SIMILARITY('%operation Knee right%',diagnosisname) DESC
  )
WHERE ROWNUM<2;

这个查询给我的输出是“左膝手术”,但我的期望是“右膝手术”。

【问题讨论】:

【参考方案1】:

请试试这个查询。这可能有助于解决您的问题。

SELECT diagnosisname 
   FROM (SELECT diagnosisname, UTL_MATCH.jaro_winkler_similarity('%operation Knee right%',diagnosisname) 
   FROM icd_code 
   WHERE UTL_MATCH.jaro_winkler_similarity('%operation Knee right%',diagnosisname) = 100
   ORDER BY UTL_MATCH.EDIT_DISTANCE_SIMILARITY('%operation Knee right%',diagnosisname) DESC) 
WHERE ROWNUM<2

【讨论】:

你好@Pankaj,你正在比较 UTL_MATCH.jaro_winkler_similarity('%operation Knee right%',diagnosisname) = 100 这意味着第一个字符串和第二个字符串都应该完全匹配。但是我的要求是,即使它部分(但几乎)匹配也应该有效。但是您的查询什么也没返回。【参考方案2】:

关于UTL_MATCH的使用有几点需要注意:

EDIT_DISTANCE_SIMILARITY:返回 0 到 100 之间的整数,其中 0 表示完全不相似,100 表示完全匹配。 JARO_WINKLER_SIMILARITY:返回 0 到 100 之间的整数,其中 0 表示完全不相似,100 表示完全匹配,但会尝试考虑可能的数据输入错误。

ORDER BY UTL_MATCH.EDIT_DISTANCE_SIMILARITY('%operation Knee right%',diagnosisname) DESC

这不会给你正确的结果。因为,您只考虑可能的相似性,而没有考虑数据输入错误。因此,您必须使用 JARO_WINKLER_SIMILARITY

右膝手术

您需要记住输入的 CASE 和要比较的列值。它们必须在相似的情况下才能正确匹配。您在 LOWERCASE 中传递输入,但是,您的列值在 INITCAP 中。更好地将列值和输入转换为类似的情况。

我们看下面的演示来了解一下:

SQL> WITH DATA AS(
  2  SELECT 'Heart Operation' diagnosis_name, 'IH123' icd_code FROM dual UNION ALL
  3  SELECT 'Knee Operation' diagnosis_name, 'IK123' icd_code FROM dual UNION ALL
  4  SELECT 'Left Knee Operation' diagnosis_name, 'IKL123' icd_code FROM dual UNION ALL
  5  SELECT 'Right Knee Operation' diagnosis_name, 'IKR123' icd_code FROM dual UNION ALL
  6  SELECT 'Fever' diagnosis_name, 'IF123' icd_code FROM dual
  7  )
  8  SELECT t.*,
  9    utl_match.edit_distance_similarity(upper(diagnosis_name),upper('operation Knee right')) eds,
 10    UTL_MATCH.jaro_winkler_similarity (upper(diagnosis_name),upper('operation Knee right')) jws
 11  FROM DATA t
 12  ORDER BY jws DESC
 13  /

DIAGNOSIS_NAME       ICD_CO        EDS        JWS
-------------------- ------ ---------- ----------
Right Knee Operation IKR123         20         72
Knee Operation       IK123          20         70
Heart Operation      IH123          25         68
Left Knee Operation  IKL123         25         64
Fever                IF123          15         47

SQL>

因此,您会看到两者之间的不同之处。 jaro_winkler_similarity 在识别数据输入错误和提供最接近的匹配方面做得更好。在此基础上,只需将第一行按降序排序即可:

SQL> WITH DATA AS(
  2  SELECT 'Heart Operation' diagnosis_name, 'IH123' icd_code FROM dual UNION ALL
  3  SELECT 'Knee Operation' diagnosis_name, 'IK123' icd_code FROM dual UNION ALL
  4  SELECT 'Left Knee Operation' diagnosis_name, 'IKL123' icd_code FROM dual UNION ALL
  5  SELECT 'Right Knee Operation' diagnosis_name, 'IKR123' icd_code FROM dual UNION ALL
  6  SELECT 'Fever' diagnosis_name, 'IF123' icd_code FROM dual
  7  )
  8  SELECT diagnosis_name
  9  FROM
 10    (SELECT t.*,
 11      utl_match.edit_distance_similarity(upper(diagnosis_name),upper('operation Knee right')) eds,
 12      UTL_MATCH.jaro_winkler_similarity (upper(diagnosis_name),upper('operation Knee right')) jws
 13    FROM DATA t
 14    ORDER BY jws DESC
 15    )
 16  WHERE rownum = 1
 17  /

DIAGNOSIS_NAME
--------------------
Right Knee Operation

SQL>

【讨论】:

嗨@Lalit,您的查询工作正常,但用户也可以输入 operation crime rt 而不是 operation crime right。左=lt,右=lt等, @shary.sharath 您可以使用DECODE 自定义一些东西。该功能为您提供最接近的匹配,但很少有超出该功能范围的内容。您需要显式编写查询来处理可能存在歧义的情况。例如,operation knee rt 将给出两行,因为两者都是紧密匹配的。但是,如果您将rt 解码为right 并将lt 解码为left,您将获得所需的输出。请将其标记为已回答。 您好@Lalit,我使用了您的查询SELECT diagnosisname FROM ( SELECT diagnosisname,utl_match.edit_distance_similarity(UPPER(diagnosisname),UPPER('knee operation Left ')) eds, UTL_MATCH.jaro_winkler_similarity (UPPER(diagnosisname),UPPER('knee operation Left ')) jws FROM icd_code ORDER BY jws DESC ) WHERE ROWNUM = 1,但它返回的是膝盖操作而不是左膝盖操作。我现在该怎么办? 嗯,那是因为Knee Operation 与前两个词完美匹配。让我给你一个解决方法,同时你可以试试这个lalitkumarb.wordpress.com/2014/12/02/…你可以将字符串拆分为单个单词并使用IN运算符进行比较。 对于句子中的单词匹配 jaro 或编辑哪个会更好?

以上是关于如何从 Oracle 表中获取几乎匹配的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用oracle程序将数据从多个表中插入一个表中

Oracle regexp_replace 挑选出模式匹配组

如何从另一张表中获取完全匹配的数据?

如何从 SQL Server 中的表中获取不匹配的数据

Oracle:比较两个不同表中没有主键的字符串列以查找匹配/不匹配的字符串

如何从oracle中的多个表中获取值,包括日期