Pregunta

He implementado el "MOD 10" check algoritmo dígitos utilizando SQL, para el Servicio Postal de Estados Unidos Dirección del Servicio de cambio Keyline según el método en su documento, pero parece que estoy recibiendo los números equivocados! Nuestras cadenas de entrada sólo tienen números en ellos, por lo que el cálculo un poco más fácil. Cuando comparo mis resultados con los resultados de las pruebas de su aplicación, me sale un número diferente. No entiendo lo que está pasando? ¿Alguien ve algo malo en mi algoritmo? Tiene que ser algo obvio ...

La documentación para el método se puede encontrar en la página 12-13 de este documento: http://www.usps.com/cpim/ftp/pubs/pub8a. pdf

La aplicación de ejemplo se puede encontrar en: http://ribbs.usps.gov/acs/documents/tech_guides/KEYLINE. EXE

NOTA: He arreglado el código siguiente, en base a la ayuda de los usuarios del foro. Esto es para que los lectores del futuro serán capaces de utilizar el código en su totalidad.

ALTER function [dbo].[udf_create_acs] (@MasterCustomerId varchar(26))
returns varchar(30)
as
begin
    --this implements the "mod 10" check digit calculation
    --for the US Postal Service ACS function, from "Publication 8A"
    --found at "http://www.usps.com/cpim/ftp/pubs/pub8a.pdf"
    declare @result varchar(30)
    declare @current_char int
    declare @char_positions_odd varchar(10)
    declare @char_positions_even varchar(10)
    declare @total_value int
    declare @check_digit varchar(1)

    --These strings represent the pre-calculated values of each character
    --Example: '7' in an odd position in the input becomes 14, which is 1+4=5
    -- so the '7' is in position 5 in the string - zero-indexed
    set @char_positions_odd = '0516273849'
    set @char_positions_even = '0123456789'
    set @total_value = 0
    set @current_char = 1

    --stepping through the string one character at a time
    while (@current_char <= len(@MasterCustomerId)) begin
        --this is the calculation for the character's weighted value
        if (@current_char % 2 = 0) begin
            --it is an even position, so just add the digit's value
            set @total_value = @total_value + convert(int, substring(@MasterCustomerId, @current_char, 1))
        end else begin
            --it is an odd position, so add the pre-calculated value for the digit
            set @total_value = @total_value + (charindex(substring(@MasterCustomerId, @current_char, 1), @char_positions_odd) - 1)
        end

        set @current_char = @current_char + 1
    end

    --find the check digit (character) using the formula in the USPS document
    set @check_digit = convert(varchar,(10 - (@total_value % 10)) % 10)

    set @result = '#' + @MasterCustomerId + '   ' + @check_digit + '#'

    return @result
end
¿Fue útil?

Solución

set @check_digit = convert(varchar, (10 - (@total_value % 10)) % 10)

Otros consejos

No estoy seguro de por qué te estás metiendo toda la cadena de representaciones cuando se trabaja en un lenguaje basado en conjunto.

Probablemente lo haría como a continuación. Corrí a través de cuatro pruebas y todos fueron un éxito. Puede ampliar esta facilidad para manejar caracteres, así y que incluso podría hacer que la tabla permanente si realmente quería hacer eso.

CREATE FUNCTION dbo.Get_Mod10
(
    @original_string    VARCHAR(26)
)
RETURNS VARCHAR(30)
AS
BEGIN
    DECLARE
        @value_mapping TABLE (original_char CHAR(1) NOT NULL, odd_value TINYINT NOT NULL, even_value TINYINT NOT NULL)

    INSERT INTO @value_mapping
    (
        original_char,
        odd_value,
        even_value
    )
    SELECT '0', 0, 0 UNION
    SELECT '1', 2, 1 UNION
    SELECT '2', 4, 2 UNION
    SELECT '3', 6, 3 UNION
    SELECT '4', 8, 4 UNION
    SELECT '5', 1, 5 UNION
    SELECT '6', 3, 6 UNION
    SELECT '7', 5, 7 UNION
    SELECT '8', 7, 8 UNION
    SELECT '9', 9, 9

    DECLARE
        @i              INT,
        @clean_string   VARCHAR(26),
        @len_string     TINYINT,
        @sum            SMALLINT

    SET @clean_string = REPLACE(@original_string, ' ', '')
    SET @len_string = LEN(@clean_string)
    SET @i = 1
    SET @sum = 0

    WHILE (@i <= @len_string)
    BEGIN
        SELECT
            @sum = @sum + CASE WHEN @i % 2 = 0 THEN even_value ELSE odd_value END
        FROM
            @value_mapping
        WHERE
            original_char = SUBSTRING(@clean_string, @i, 1)

        SET @i = @i + 1
    END

    RETURN (10 - (@sum % 10)) % 10
END
GO

¿Por qué tenemos un mod adicional:

convertir (varchar, 10% << -?

El documento dice que sólo el último dígito debe ser restado de 10. ¿Me he perdido algo?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top