0

我在 PL/SQL 中编写了一个例程来尝试匹配可能存在印刷/数据输入错误的日期。

它有效,但我想看看是否有人有其他/更好的想法。该例程不需要在 PL/SQL 中,因为我阅读了许多语言。

  FUNCTION FUZZY_DATE_MATCH(IN_DATE_1 DATE, IN_DATE_2 DATE) RETURN NUMBER AS
    MONTH_1 NUMBER(2);
    MONTH_2 NUMBER(2);
    DAY_1 NUMBER(2);
    DAY_2 NUMBER(2);
    YEAR_1 NUMBER(4);
    YEAR_2 NUMBER(4);
    MATCH_SCORE NUMBER(3) := 0;
  BEGIN
    IF TRUNC(IN_DATE_1) = TRUNC(IN_DATE_2)
    THEN
      MATCH_SCORE := 100;
    ELSE
      IF ABS(TRUNC(IN_DATE_1) - TRUNC(IN_DATE_2)) < 2
      THEN
        MATCH_SCORE :=50;
      ELSE
        MONTH_1 := TO_NUMBER(TO_CHAR(IN_DATE_1,'MM'));
        MONTH_2 := TO_NUMBER(TO_CHAR(IN_DATE_2,'MM'));
        IF MONTH_1 = MONTH_2
        THEN
          MATCH_SCORE := MATCH_SCORE + 15;
        ELSE
          IF (ABS(MONTH_1 - MONTH_2) < 2) OR
             (TO_NUMBER(SUBSTR(LPAD(MONTH_1,2,'0'),2,1)||SUBSTR(LPAD(MONTH_1,2,'0'),1,1)) = MONTH_2)
          THEN
            MATCH_SCORE := MATCH_SCORE + 7;
          END IF;
        END IF;
        DAY_1 := TO_NUMBER(TO_CHAR(IN_DATE_1,'DD'));
        DAY_2 := TO_NUMBER(TO_CHAR(IN_DATE_2,'DD'));
        IF DAY_1 = DAY_2
        THEN
          MATCH_SCORE := MATCH_SCORE + 10;
        ELSE
          IF (ABS(DAY_1 - DAY_2) < 2) OR
             (TO_NUMBER(SUBSTR(LPAD(DAY_1,2,'0'),2,1)||SUBSTR(LPAD(DAY_1,2,'0'),1,1)) = DAY_2)
          THEN
            MATCH_SCORE := MATCH_SCORE + 5;
          END IF;
        END IF;
        YEAR_1 := TO_NUMBER(TO_CHAR(IN_DATE_1,'YYYY'));
        YEAR_2 := TO_NUMBER(TO_CHAR(IN_DATE_2,'YYYY'));
        IF YEAR_1 = YEAR_2
        THEN
          MATCH_SCORE := MATCH_SCORE + 25;
        ELSE
          IF (ABS(YEAR_1 - YEAR_2) < 2) OR
             (TO_NUMBER(SUBSTR(LPAD(YEAR_1,2,'0'),4,1)||SUBSTR(LPAD(YEAR_1,2,'0'),3,1)) = TO_NUMBER(SUBSTR(TO_CHAR(YEAR_2),3)))
          THEN
            MATCH_SCORE := MATCH_SCORE + 12;
          END IF;
        END IF;
      END IF;
    END IF;
    RETURN MATCH_SCORE;
  END FUZZY_DATE_MATCH;

基本概念是比较两个日期并返回一个介于 0 和 100 之间的值,其中 100 是完全匹配,0 是不匹配。我正在寻找的错误类型是个位数错误和转置错误。我的假设是年比月重,而月又比天重。

我尝试使用谷歌搜索模糊日期匹配,但答案通常处理日期之间的距离,而不是数据输入错误。

A感谢所有帮助。

保罗

4

3 回答 3

1

无需自己实现。查看作为 Oracle 标准部分的 UTL_MATCH 包。这是一个快速的总结:

FUNCTION edit_distance(s1 IN VARCHAR2, s2 IN VARCHAR2)
                       RETURN pls_integer;
  -- Computes the Levenshtein distance between s1 and s2.

FUNCTION jaro_winkler(s1 IN VARCHAR2, s2 IN VARCHAR2)
                      RETURN binary_double;
  -- Similar to Levenshtein distance, but tries to account for mis-typings,
  -- character swaps, etc.

FUNCTION edit_distance_similarity(s1 IN VARCHAR2, s2 IN VARCHAR2)
                                  RETURN pls_integer;
  -- Similar to Levenshtein distance, but returns an integer from 0 to 100
  -- where 0 means no similarity and 100 means the strings are identical.

FUNCTION jaro_winkler_similarity(s1 IN VARCHAR2, s2 IN VARCHAR2)
                                 RETURN pls_integer;
  -- Similar to above, but based on Jaro-Winkler.

这是一个简单的例子:

SELECT UTL_MATCH.EDIT_DISTANCE('potato', 'tomato') AS lev,
       UTL_MATCH.EDIT_DISTANCE_SIMILARITY('potato', 'tomato') AS lev_sim,
       TO_NUMBER(UTL_MATCH.JARO_WINKLER('potato', 'tomato')) AS jw,
       UTL_MATCH.JARO_WINKLER_SIMILARITY('potato', 'tomato') jw_sim
  FROM DUAL;

听起来你可能可以使用 JARO_WINKLER_SIMILARITY。将两个日期都转换为标准字符串表示(例如 TO_CHAR(aDate, 'DD/MM/YYYY HH24:MI:SS')),然后比较它们。

(顺便说一句 -TO_NUMBER应用于结果是JARO_WINKLER因为 OracleORA-031115 : unsupported network datatype or representation在调用 JARO_WINKLER 时会抛出一个,因为它返回一个 BINARY_DOUBLE,Windows 平台上的 Oracle 接口例程似乎无法处理。那么,如果可以,为什么要使用该类型? t 使用类型? ??? :-)

分享和享受。

于 2013-05-03T10:55:39.913 回答
0

我进行了相同的搜索,因此我将分享我的日期函数版本`参见代码 DateMatch:

 CREATE Function [fn_DateMatch] (@dt1 DateTime, @dt2 DateTime)
 RETURNS FLOAT 
   AS 
 BEGIN
 DECLARE @Result FLOAT, @yyyy1 NUMERIC, @yyyy2 NUMERIC, @mm1 NUMERIC, @mm2 NUMERIC, @dd1 NUMERIC, @dd2 NUMERIC, @threshold NUMERIC  
   SELECT @Result = 0, @threshold = 85 
   IF @dt1 = @dt2 SET @Result = 100 
   IF (@Result < 100) SET @Result = 100-abs(DATEDIFF (DAY,@dt1, @dt2)) 
   IF (@Result < @threshold)
   BEGIN 
     SELECT @yyyy1 = CONVERT (INT, DATEPART (year, @dt1)), @mm1 = CONVERT  (INT, DATEPART (month, @dt1)), @dd1 = CONVERT  (INT, DATEPART (day, @dt1)) 
          , @yyyy2 = CONVERT (INT, DATEPART (year, @dt2)), @mm2 = CONVERT  (INT, DATEPART (month, @dt2)), @dd2 = CONVERT  (INT, DATEPART (day, @dt2))
     SET @Result = 100-((@yyyy1+@yyyy2)*3.0+(@mm1+@mm2)*3.0+(@dd1+@dd2)*1.0)*3
     IF (@Result < @threshold) and @yyyy1=@yyyy2 and @mm1+@dd1=@mm2+@dd2 SET @Result = 90
   END 
   IF (@Result < @threshold) 
     BEGIN  
     IF convert(varchar, @dt1, 108) <> '00:00:00' and convert(varchar, @dt2, 108) <> '00:00:00' 
        BEGIN
          SET @Result = 100-((CONVERT(float, dbo.fn_levenshtein (convert(varchar, @dt1, 120), convert(varchar, @dt2, 120)))/CONVERT(float,len(convert(varchar, @dt2, 120))))*100) 
        END 
     ELSE  
        BEGIN 
          SET @Result = 100-((CONVERT(float, dbo.fn_levenshtein (convert(varchar, @dt1, 112), convert(varchar, @dt2, 112)))/CONVERT(float,len(convert(varchar, @dt2, 112))))*100) 
        END 
     END 
   RETURN @Result 
 END;`
于 2014-02-20T08:22:04.107 回答
0

如果您正在纠正数据输入错误,那么加权不同的日期部分可能没有任何优势 - 我假设年份部分和日期部分同样可能存在键控错误。因此,这是一个模糊字符串匹配问题,而不是一个模糊日期匹配问题。

一组常用的模糊字符串匹配算法是编辑距离-汉明距离很快,但假设不正确的字符串不包含任何字符添加/删除(因此它在比较“hello”和“gello”时表现良好,但不是比较“hello”和“hhello”),而Levenshtein 距离的计算成本更高,但能够解释不正确字符串中的字符添加/删除。

于 2013-05-02T16:33:34.180 回答