我正在寻找一种方法,您可以告诉您的列中的值是否是有效的BSN值。BSN(荷兰SSN)必须符合一种“11测试”。请注意,它与银行帐户不同。请查看https://nl.wikipedia.org/wiki/Burgerservicenummer了解详细信息。
我想返回的是一个0或1,表示我的BSN是有效的(=1)还是无效的(=0)。目前它存储为一个数字。
我尝试为此创建一个SQL语句。我从以下操作开始:
1.首先,我只需要有实际值的行,并跳过(null)值:
SELECT D_BSN FROM EMPLOYEE WHERE D_BSN IS NOT NULL;
1.在那之后,我希望我的BSN是VARCHAR2。
SELECT TO_CHAR(D_BSN) FROM EMPLOYEE WHERE D_BSN IS NOT NULL;
1.现在我希望我的BSN总是相同的长度:
SELECT DECODE(LENGTH(TO_CHAR(D_BSN)),8, '0' || D_BSN, D_BSN)
FROM EMPLOYEE
WHERE D_BSN IS NOT NULL;
1.现在,如果我的长度不是9,我有一个无效的字段,所以'退出'与0。
SELECT
DECODE(
LENGTH(DECODE(LENGTH(TO_CHAR(D_BSN)),8, '0' || D_BSN, D_BSN)), 9,
DECODE(LENGTH(TO_CHAR(D_BSN)),8, '0' || D_BSN, D_BSN), 0)
FROM MW_DOCUMENTS
WHERE D_BSN IS NOT NULL;
在这一点上,我发现我的SQL语句变得不可读。也是因为我还有很长的路要走。我必须选择每个数字,乘以它的位置,总结结果,除以11,看看mod是否等于BSN的最后一个数字。这在编程语言中很容易,所以为什么不把它放在一个函数中。所以我可以这样使用它:
SELECT * FROM EMPLOYEE WHERE IS_BSN(D_BSN) = 0
得到所有无效的BSN。看看我的答案。
UPDATE:(添加了函数的代码)
下面是我的函数,它返回一个0或1,表示有效或无效的BSN:
create or replace FUNCTION is_bsn(num_in NUMBER) RETURN NUMBER IS
-- Yes is BSN = True == 1
-- NO not BSN = False == 0
checkValue NUMBER := -1;
factor NUMBER := 9;
result NUMBER := 0;
outcome NUMBER := 0;
bsn VARCHAR2(9);
BEGIN
bsn := to_char(num_in);
-- Check if length is 8 if so add zero in front
IF LENGTH(bsn) = 8 THEN
bsn := '0' || bsn;
END IF;
-- Now length should be 9
IF LENGTH(bsn) <> 9 THEN
RETURN 0;
END IF;
checkValue := TO_NUMBER(SUBSTR(bsn, 9, 1));
FOR Lcntr IN 1..8
LOOP
result := result + TO_NUMBER(SUBSTR(bsn, Lcntr, 1)) * factor;
factor := factor - 1;
END LOOP;
outcome := result mod 11;
if outcome = checkValue then
return 1;
ELSE
return 0;
END IF;
EXCEPTION
WHEN OTHERS THEN
RETURN 'FALSE';
END is_bsn;
更新:
由于Wildplasser的答案是针对Postgress的,而最初的问题是针对Oracle的,所以我将他的答案转换为Oracle:
create or replace FUNCTION is_bsn2(inBsn in NUMBER) RETURN NUMBER IS
-- Yes is BSN = True = 0
-- NO not BSN = False => 1
val NUMBER;
mul NUMBER;
bsn NUMBER := inBsn;
BEGIN
val := 11 - (bsn mod 10); -- the check digit
mul := 1;
WHILE (bsn > 0) loop
bsn := FLOOR (bsn / 10);
mul := mul + 1;
val := val + (bsn mod 10) * mul;
END LOOP;
IF (mul < 9) THEN
RETURN 13;
END IF; -- too short
RETURN val mod 11;
END;
请注意,我将其重命名为is_bsn2,并且结果〉0表示不是有效的bsn。我看不到一个比另一个有多大的性能提升,但我没有广泛地测试它。
2条答案
按热度按时间zzzyeukh1#
所有这些都可以在一个循环中完成,而无需转换为字符。
3vpjnl9f2#
对于不喜欢函数的人;下面是一个嵌入在select语句中解决方案:
用
WHERE bsn LIKE '%[0-9]%'
检查字段的格式(空值,值等),然后执行实际的11 proef。这适用于几乎任何rdbm类型。也许只是切换CAST()与CONVERT()或其他取决于你的数据库风格。