Domanda

Ho implementato il "MOD 10" check algoritmo cifre utilizzando SQL, per l'US Postal Service Indirizzo del servizio di modifica Keyline secondo il metodo a loro documento, ma sembra sto ottenendo i numeri sbagliati! I nostri stringhe di input hanno solo numeri in loro, rendendo il calcolo un po 'più facile. Quando paragono i miei risultati con i risultati della loro applicazione di test, ho numeri diversi. Non capisco cosa sta succedendo? Qualcuno vede nulla di sbagliato con il mio algoritmo? Deve essere qualcosa di ovvio ...

La documentazione per il metodo può essere trovato a pagina 12-13 di questo documento: http://www.usps.com/cpim/ftp/pubs/pub8a. pdf

L'applicazione di esempio è disponibile all'indirizzo: http://ribbs.usps.gov/acs/documents/tech_guides/KEYLINE. EXE

ATTENZIONE: ho fissato il codice qui sotto, sulla base del aiuto da parte degli utenti del forum. Questo è così che i lettori futuri saranno in grado di utilizzare il codice nella sua interezza.

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
È stato utile?

Soluzione

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

Altri suggerimenti

Non sono sicuro che il motivo per cui si sta scherzi con le intere rappresentazioni di stringa quando si lavora in un linguaggio di set-based.

probabilmente lo farei come qui di seguito. Ho eseguito quattro prove attraverso ed erano tutti di successo. È possibile espandere facilmente questo per gestire i caratteri come bene e si potrebbe anche fare il tavolo permanente se si voleva davvero farlo.

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

Perché abbiamo un mod aggiuntivo:

convert (varchar, 10% << -?

Il documento dice che solo l'ultima cifra deve essere sottratto da 10. Mi sono perso qualcosa?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top