0

在 MySQL 数据库中,我有正确和不正确的 luhn 数字(不使用 luhn 算法验证的数字)的记录。

假设错误的数字是由于一位数字的输入错误,我想获得可能正确数字的列表。目标是使用此列表过滤可能的正确记录,然后使用另一个条件再次过滤。

[编辑] 回答我自己的问题,这里是比较有效 luhn 号码和无效 luhn 号码的程序,该号码是由于一位数字 (luhn_typo(invalid, valid)) 或交换 2 位数字 (luhn_swap(invalid, valid) )。

CREATE DEFINER=`root`@`localhost` FUNCTION `luhn_sum`(p_number VARCHAR(32)) RETURNS INT(11)
SQL SECURITY INVOKER
BEGIN
    DECLARE i, mysum, r, weight INT;

    SET weight = 1;
    SET mysum = 0;
    SET i = length(p_number);

    WHILE i > 0 DO
        SET r = substring(p_number, i, 1) * weight;
        SET mysum = mysum + IF(r > 9, r - 9, r);
        SET i = i - 1;
        SET weight = 3 - weight;
    END WHILE;

    RETURN mysum;
END;

CREATE DEFINER=`root`@`localhost` FUNCTION `luhn_typo`(p_number VARCHAR(32), t_number VARCHAR(32)) RETURNS TINYINT(1)
SQL SECURITY INVOKER
BEGIN
DECLARE r, val, new_val, len, str_len, weight,digit,new_digit INT;
DECLARE new_luhn VARCHAR(255);

  IF (p_number = t_number) THEN
      RETURN FALSE;
  END IF;

  SET r = luhn_sum(p_number) % 10;

  IF (r = 0) THEN
      RETURN FALSE;
  END IF;

  SET str_len = LENGTH(p_number);
  SET len = str_len;
  SET weight = 1;

  WHILE len > 0 DO
      SET digit = CAST(SUBSTRING(p_number, len, 1) AS SIGNED) * weight;
      SET val = IF(digit > 9, digit - 9, digit);

      SET new_val = IF(val < r, val - r + 10, val - r);
      SET new_digit = (IF(weight = 2 AND (new_val % 2 = 1), new_val + 9, new_val)) / weight;

      SET new_luhn = CONCAT(SUBSTRING(p_number, 1, len - 1), new_digit, SUBSTRING(p_number, len + 1, str_len - len));

      IF (new_luhn = t_number ) THEN
          RETURN TRUE;
      END IF;

      SET weight = 3 - weight;
      SET len = len - 1;
  END WHILE;

  RETURN  FALSE;
END;

CREATE DEFINER=`root`@`localhost` FUNCTION `luhn_swap`(p_number VARCHAR(32), t_number VARCHAR(32)) RETURNS VARCHAR(32) CHARSET latin1
  SQL SECURITY INVOKER
BEGIN
  DECLARE parity, r, pair_sum_delta, len INT;
  DECLARE digit_pair, str_len VARCHAR(2);

  IF (p_number = t_number) THEN
      RETURN FALSE;
  END IF;

  SET r = luhn_sum(p_number) % 10;

  IF (r = 0) THEN
      RETURN FALSE;
  END IF;

  SET str_len = LENGTH(p_number);
  SET len = str_len;
  SET parity = 1; -- odd

  WHILE len > 1 DO
      SET digit_pair = SUBSTRING(p_number, len - 1, 2);
      SET pair_sum_delta = (-luhn_sum(digit_pair) + luhn_sum(REVERSE(digit_pair))) * parity;

      IF ((r + pair_sum_delta) % 10 = 0) AND (t_number = CONCAT(SUBSTRING(p_number, 1, len -2), REVERSE(digit_pair), SUBSTRING(p_number, len + 1, str_len - len))) THEN
            RETURN TRUE;
      END IF;

      SET parity = -parity;
      SET len = len -1;    
  END WHILE;

  RETURN FALSE;
END;
4

0 回答 0