T-SQL :: 生成随机的瑞士国民身份证号码 (AHV/AVS)
T-SQL :: generate random Swiss National Identification Number (AHV/AVS)
我想生成随机的瑞士国民身份证号码 (AHV/AVS)。
我找到了一个 can do that and if I look at the source code of the same page I can alos see the JavaScript
code that can generate it.
的网站
数字是按照以下模式生成的:
756
: 是前缀号,永远不变
1234
: 是一个随机数
5678
: 是一个随机数
9
: 是一个随机数
7
:就是这个计算产生的控制号:
- 从第一个数字开始,每隔一个数字求和:
7 + 6 + 2 + 4 + 6 + 8
= 33
- 从 drcond 数开始,每隔一个数取其和:
5 + 1 + 3 + 5 + 7 + 9
= 30
- 然后将第二个数
x 3
相乘并对第一个数求和: 33 + (30 x 3)
= 123
- 现在让
10
减去那个数的模:10-(123%10)
= 10-3
= 7
===> And this is how we finally have obtained 7
which is the last number <===
我创建了一个SQL命令可以生成我需要的随机数:
SELECT CONCAT('756.',
FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000) , '.',
FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000) , '.',
ABS(CHECKSUM(NEWID()))%10
-- How to select one number out of two?
)
此代码生成我需要的所有随机数,但我不知道如何 select 二选一。
不知道T-SQL
能不能解析数字和select二选一
首先,您当前的逻辑存在缺陷,您得到了一个介于 0 和 9999 之间的随机数,但是您没有将该值设置为固定宽度。因此,如果您的随机数是 7
、9
和 2
,您最终会得到 792
而不是 00700090002
。您需要添加前导零。我使用 CONCAT
和 RIGHT
.
接下来,我将表达式移到 FROM
中,使其具体化并易于使用。然后我们可以使用 SUBSTRING
和 CONVERT
来获取你的数字的 2 部分和 SUM
它们,然后最后应用最终逻辑。然后我将句点注入字符串。
SELECT V.NIN,
STUFF(STUFF(STUFF(CONCAT(V.NIN,10 - ((Odds + (Evens * 3)) % 10)),12,0,'.'),8,0,'.'),4,0,'.')
FROM (VALUES(CONCAT(RIGHT(CONCAT('000','756'),3),
RIGHT(CONCAT('0000',FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)),4),
RIGHT(CONCAT('0000',FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)),4),
ABS(CHECKSUM(NEWID()))%10)),
('756123456789'))V(NIN)
CROSS APPLY (VALUES(CONVERT(int,SUBSTRING(V.NIN,1,1)) + CONVERT(int,SUBSTRING(V.NIN,3,1)) + CONVERT(int,SUBSTRING(V.NIN,5,1)) + CONVERT(int,SUBSTRING(V.NIN,7,1)) + CONVERT(int,SUBSTRING(V.NIN,9,1)) + CONVERT(int,SUBSTRING(V.NIN,11,1)),
CONVERT(int,SUBSTRING(V.NIN,2,1)) + CONVERT(int,SUBSTRING(V.NIN,4,1)) + CONVERT(int,SUBSTRING(V.NIN,6,1)) + CONVERT(int,SUBSTRING(V.NIN,8,1)) + CONVERT(int,SUBSTRING(V.NIN,10,1)) + CONVERT(int,SUBSTRING(V.NIN,12,1))))I(Odds,Evens)
但是,老实说,我建议这可能适合您的应用程序,而不是 SQL。
此实现使用整数计算而不是子字符串来获取数字。
注意:我在校验位计算的最终结果中加上了%10,转换为10 -> 0。
-- Format Number
SELECT *, CAST( Prefix AS CHAR( 3 )) + '.' + CAST( Rnd1 AS CHAR( 4 )) + '.' + CAST( Rnd2 AS CHAR( 4 )) + '.' + CAST( Rnd3 AS CHAR( 1 )) + CAST( CheckDigit AS CHAR( 1 )) AS FinalNum
FROM(
-- Step 2: calculate check digit. NOTE: I apply %10 to the result to convert 10 to 0
SELECT *, ( 10 - (( OddDigits + ( EvenDigits ) * 3 ) % 10 )) % 10 AS CheckDigit
FROM
-- Step 2: calculate Odd / Even digit sum. Note that prefix is hardcoded to 756
( SELECT Prefix, Rnd1, Rnd2, Rnd3,
7 + 6 + (( Rnd1 % 1000 ) / 100 ) + ( Rnd1 % 10 ) + (( Rnd2 % 1000 ) / 100 ) + ( Rnd2 % 10 ) AS OddDigits,
5 + ( Rnd1 / 1000 ) + (( Rnd1 % 100 ) / 10 ) + ( Rnd2 / 1000 ) + (( Rnd2 % 100 ) / 10 ) + Rnd3 AS EvenDigits
FROM
-- Step 1: initial random values. Note that prefix is hardcoded to 756
( VALUES( 756,
CAST( FLOOR( RAND( CHECKSUM( NEWID())) * ( 9999 - 1000 ) + 1000 ) AS INT ),
CAST( FLOOR( RAND( CHECKSUM( NEWID())) * ( 9999 - 1000 ) + 1000 ) AS INT ),
ABS( CHECKSUM( NEWID())) % 10 ),
-- Your original example. Should be removed in production code
(756, 1234, 5678, 9)) AS RndNum( Prefix, Rnd1, Rnd2, Rnd3 )
) AS CtrlDigitCalculation
) AS FormattedNumber
结果
Prefix Rnd1 Rnd2 Rnd3 OddDigits EvenDigits CheckDigit FinalNum
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------------
756 3826 4185 8 34 34 9 756.8002.7335.52
756 1234 5678 9 33 30 7 756.1234.5678.97
更新
检查了随机数生成器表达式的return值,发现它可以return一个5位数的值,即10000。
SELECT CAST( FLOOR( CAST( 1.0 AS FLOAT ) * ( 9999 - 1000 + 1 ) + 1000 ) AS INT )
-- Result: 10000
要修复它,您需要删除“+ 1”:
SELECT CAST( FLOOR( CAST( 1.0 AS FLOAT ) * ( 9999 - 1000 ) + 1000 ) AS INT )
-- Result: 9999
另一种生成带有控制号的随机 SNIN 的方法。
使用的技巧是交叉应用,用数值计算赔率和偶数的总和。
select concat(code, ctrl) as SNIN
from (values
(concat('756','.', right(format(rand()*100000,'0000'),4)
,'.', right(format(rand()*100000,'0000'),4)
,'.', right(format(rand()*100,'0'),1)))
, ('756.1234.5678.9')
, ('756.1917.1051.7')
) v(code)
cross apply (
select (10-(sum(odds)+(3*sum(evens)))%10)%10 as ctrl
from (
select
cast(substring(code_nr,(n*2)+1,1) as int) as odds
, cast(substring(code_nr,(n+1)*2,1) as int) as evens
from (values (0),(1),(2),(3),(4),(5)) as nums(n)
cross join (select replace(code,'.','')) as code(code_nr)
) q
) ca;
SNIN
756.9357.6870.03
756.1234.5678.97
756.1917.1051.70
演示 db<>fiddle here
我想生成随机的瑞士国民身份证号码 (AHV/AVS)。
我找到了一个 can do that and if I look at the source code of the same page I can alos see the JavaScript
code that can generate it.
数字是按照以下模式生成的:
756
: 是前缀号,永远不变1234
: 是一个随机数5678
: 是一个随机数9
: 是一个随机数7
:就是这个计算产生的控制号:- 从第一个数字开始,每隔一个数字求和:
7 + 6 + 2 + 4 + 6 + 8
=33
- 从 drcond 数开始,每隔一个数取其和:
5 + 1 + 3 + 5 + 7 + 9
=30
- 然后将第二个数
x 3
相乘并对第一个数求和:33 + (30 x 3)
=123
- 现在让
10
减去那个数的模:10-(123%10)
=10-3
=7
- 从第一个数字开始,每隔一个数字求和:
===> And this is how we finally have obtained
7
which is the last number <===
我创建了一个SQL命令可以生成我需要的随机数:
SELECT CONCAT('756.',
FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000) , '.',
FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000) , '.',
ABS(CHECKSUM(NEWID()))%10
-- How to select one number out of two?
)
此代码生成我需要的所有随机数,但我不知道如何 select 二选一。
不知道T-SQL
能不能解析数字和select二选一
首先,您当前的逻辑存在缺陷,您得到了一个介于 0 和 9999 之间的随机数,但是您没有将该值设置为固定宽度。因此,如果您的随机数是 7
、9
和 2
,您最终会得到 792
而不是 00700090002
。您需要添加前导零。我使用 CONCAT
和 RIGHT
.
接下来,我将表达式移到 FROM
中,使其具体化并易于使用。然后我们可以使用 SUBSTRING
和 CONVERT
来获取你的数字的 2 部分和 SUM
它们,然后最后应用最终逻辑。然后我将句点注入字符串。
SELECT V.NIN,
STUFF(STUFF(STUFF(CONCAT(V.NIN,10 - ((Odds + (Evens * 3)) % 10)),12,0,'.'),8,0,'.'),4,0,'.')
FROM (VALUES(CONCAT(RIGHT(CONCAT('000','756'),3),
RIGHT(CONCAT('0000',FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)),4),
RIGHT(CONCAT('0000',FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)),4),
ABS(CHECKSUM(NEWID()))%10)),
('756123456789'))V(NIN)
CROSS APPLY (VALUES(CONVERT(int,SUBSTRING(V.NIN,1,1)) + CONVERT(int,SUBSTRING(V.NIN,3,1)) + CONVERT(int,SUBSTRING(V.NIN,5,1)) + CONVERT(int,SUBSTRING(V.NIN,7,1)) + CONVERT(int,SUBSTRING(V.NIN,9,1)) + CONVERT(int,SUBSTRING(V.NIN,11,1)),
CONVERT(int,SUBSTRING(V.NIN,2,1)) + CONVERT(int,SUBSTRING(V.NIN,4,1)) + CONVERT(int,SUBSTRING(V.NIN,6,1)) + CONVERT(int,SUBSTRING(V.NIN,8,1)) + CONVERT(int,SUBSTRING(V.NIN,10,1)) + CONVERT(int,SUBSTRING(V.NIN,12,1))))I(Odds,Evens)
但是,老实说,我建议这可能适合您的应用程序,而不是 SQL。
此实现使用整数计算而不是子字符串来获取数字。
注意:我在校验位计算的最终结果中加上了%10,转换为10 -> 0。
-- Format Number
SELECT *, CAST( Prefix AS CHAR( 3 )) + '.' + CAST( Rnd1 AS CHAR( 4 )) + '.' + CAST( Rnd2 AS CHAR( 4 )) + '.' + CAST( Rnd3 AS CHAR( 1 )) + CAST( CheckDigit AS CHAR( 1 )) AS FinalNum
FROM(
-- Step 2: calculate check digit. NOTE: I apply %10 to the result to convert 10 to 0
SELECT *, ( 10 - (( OddDigits + ( EvenDigits ) * 3 ) % 10 )) % 10 AS CheckDigit
FROM
-- Step 2: calculate Odd / Even digit sum. Note that prefix is hardcoded to 756
( SELECT Prefix, Rnd1, Rnd2, Rnd3,
7 + 6 + (( Rnd1 % 1000 ) / 100 ) + ( Rnd1 % 10 ) + (( Rnd2 % 1000 ) / 100 ) + ( Rnd2 % 10 ) AS OddDigits,
5 + ( Rnd1 / 1000 ) + (( Rnd1 % 100 ) / 10 ) + ( Rnd2 / 1000 ) + (( Rnd2 % 100 ) / 10 ) + Rnd3 AS EvenDigits
FROM
-- Step 1: initial random values. Note that prefix is hardcoded to 756
( VALUES( 756,
CAST( FLOOR( RAND( CHECKSUM( NEWID())) * ( 9999 - 1000 ) + 1000 ) AS INT ),
CAST( FLOOR( RAND( CHECKSUM( NEWID())) * ( 9999 - 1000 ) + 1000 ) AS INT ),
ABS( CHECKSUM( NEWID())) % 10 ),
-- Your original example. Should be removed in production code
(756, 1234, 5678, 9)) AS RndNum( Prefix, Rnd1, Rnd2, Rnd3 )
) AS CtrlDigitCalculation
) AS FormattedNumber
结果
Prefix Rnd1 Rnd2 Rnd3 OddDigits EvenDigits CheckDigit FinalNum
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------------
756 3826 4185 8 34 34 9 756.8002.7335.52
756 1234 5678 9 33 30 7 756.1234.5678.97
更新
检查了随机数生成器表达式的return值,发现它可以return一个5位数的值,即10000。
SELECT CAST( FLOOR( CAST( 1.0 AS FLOAT ) * ( 9999 - 1000 + 1 ) + 1000 ) AS INT )
-- Result: 10000
要修复它,您需要删除“+ 1”:
SELECT CAST( FLOOR( CAST( 1.0 AS FLOAT ) * ( 9999 - 1000 ) + 1000 ) AS INT )
-- Result: 9999
另一种生成带有控制号的随机 SNIN 的方法。
使用的技巧是交叉应用,用数值计算赔率和偶数的总和。
select concat(code, ctrl) as SNIN
from (values
(concat('756','.', right(format(rand()*100000,'0000'),4)
,'.', right(format(rand()*100000,'0000'),4)
,'.', right(format(rand()*100,'0'),1)))
, ('756.1234.5678.9')
, ('756.1917.1051.7')
) v(code)
cross apply (
select (10-(sum(odds)+(3*sum(evens)))%10)%10 as ctrl
from (
select
cast(substring(code_nr,(n*2)+1,1) as int) as odds
, cast(substring(code_nr,(n+1)*2,1) as int) as evens
from (values (0),(1),(2),(3),(4),(5)) as nums(n)
cross join (select replace(code,'.','')) as code(code_nr)
) q
) ca;
SNIN |
---|
756.9357.6870.03 |
756.1234.5678.97 |
756.1917.1051.70 |
演示 db<>fiddle here