在 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;