Answers for "SQL command for the MOD10 Validation"
https://ask.sqlservercentral.com/questions/42659/sql-command-for-the-mod10-validation.html
The latest answers for the question "SQL command for the MOD10 Validation"Answer by Oleg
https://ask.sqlservercentral.com/answers/42661/view.html
<p>Here it goes:</p><pre> -- declare test variables
declare @cc varchar(23);
declare @len int;
-- set test variables values
select @cc = '37347497262302553647921', @len = len(@cc);
if
(
select
sum
(
case
when (@len - record_no) % 2 = 1 then
case
when digit * 2 > 9 then digit * 2 - 9
else digit * 2
end
else digit
end
) result
from
(
select top (@len)
row_number() over (order by [object_id]) record_no,
substring(@cc, row_number() over
(order by [object_id]), 1) digit
from sys.objects
) t
) % 10 = 0
select 'valid'
else
select 'invalid';
go</pre><p>Just restate it as you see fit. The number provided in the sample results in the valid combination compliant with CC10 a.k.a. MOD10 algorithm.</p><p>In your case, you probably want to consider passing the 22 digits and one more zero on the right of it to the guts of the select statement, which returns the sum. Take 10 - (mod 10 of it) and you will get the value of the rightmost digit as it should be in place of zero.</p><p><\!-- **Begin Edit**</p><p>Here is the inline scalar function calculating the value of the control digit. For example, if your final number has to be CC10 compliant 23 digits number and you already know your 22 digits input then pass these 22 digits as a parameter to the function and it will return the value of the control digit. The latter can then be used to append to the right of the original input. You can use less digits if you need to but not more. A good way to check the validity of the function below is you pass any of your existing credit card numbers (except the last digit) as a parameter to it and the function will "reveal" the value of the last digit on your card. Since the function operates with assumption that the input does not include the control number (of course), the logic to pick the numbers to interrogate by the algorithm steps is reversed from the one in the original validation query above, the one which did need the control number to be already included and simply stated whether the whole bunch is compliant or not. Here is the function definition:</p><pre> /*
This function calculates the value of the control number using
CC10 a.k.a. MOD10 algorithm. It expects an input of up to 22
digits passed into the function as varchar. Since this function
calculates control number rather than validating the input, the
logic to pick the numbers to interrogate is reversed( digit * 2
and if greater than 9 then reduce by 9 else leave digit * 2 alone).
In other words, this function expects an input which does not
include a control (rightmost) digit, and calculates the value of
that control digit. Then the calling code can append the returned
control digit to the right of the original input thus getting the
whole CC10 compliant result. To test this function, just pass the
digits of any of your credit cards (without the rightmost digit)
and the function will return the number matching that last digit
on your card.
*/
create function dbo.udf_CalculateMod10ControlNumber (@input varchar(22))
returns int
as
begin;
return
(
select (10 -
sum
(
case
when (len(@input) - record_no) % 2 = 0 then
case
when digit * 2 > 9 then digit * 2 - 9
else digit * 2
end
else digit
end
) % 10) % 10 result
from
(
select top (len(@input))
row_number() over (order by [object_id]) record_no,
substring(@input, row_number() over
(order by [object_id]), 1) digit
from sys.objects
) t
);
end;
go</pre><pre> -- test. Let's assume that there is an American Express
-- card 3788-749649-42835. Passing the first 14 digit to the
-- function (no spaces or dashes) should return 5 and it does
select dbo.udf_CalculateMod10ControlNumber('37887496494283');
result
-----------
5</pre><p>Of course in reality it would be far better to maintain a tiny Tally table instead of interrogating the sys.objects every time the function is called. For example,</p><pre> -- create a small table which can be used by the function
create table dbo.TinyTally(N int not null identity(1, 1) primary key clustered);
go
-- insert 23 records into it
insert into dbo.TinyTally default values;
go 23
-- now the bottom select currently stating
select top (len(@input))
row_number() over (order by [object_id]) record_no,
substring(@input, row_number() over
(order by [object_id]), 1) digit
from sys.objects
-- can be reduced to
select top (len(@input))
N record_no,
substring(@input, N, 1) digit
from dbo.TinyTally</pre><p>**End Edit** --> </p><p><\!-- **Begin Edit 2**</p><p>Here is the version which will work for SQL Server 2000. This is reduced to work only with 22 character inputs because I don't remember whether SQL Server 2000 lets you pass a variable into **select top (@n)** or not. If it does though then please replace the **select top 22** part with the original **select top (len(@input))**. Here is the script:</p><pre> create function dbo.udf_CalculateMod10ControlNumber2K (@input varchar(22))
returns int
as
begin;
return
(
select (10 -
sum
(
case
when (len(@input) - record_no) % 2 = 0 then
case
when digit * 2 > 9 then digit * 2 - 9
else digit * 2
end
else digit
end
) % 10) % 10 result
from
(
select top 22 -- (len(@input))
N record_no, substring(@input, N, 1) digit
from dbo.TinyTally
) t
);
end;
go</pre><p>The above assumes that TinyTally table already exists and has 23 (or more) records in it.</p><p>**End Edit 2** --> </p><p>
Oleg</p>Tue, 28 Jun 2011 14:46:07 GMTOleg