2009-02-19 5 views
0

J'ai implémenté l'algorithme de chiffre de contrôle "MOD 10" en utilisant SQL, pour le service de changement d'adresse US Postal Service selon la méthode dans leur document, mais il semble que je reçois les mauvais numéros! Nos chaînes d'entrée ne contiennent que des nombres, ce qui facilite le calcul. Lorsque je compare mes résultats avec les résultats de leur application de test, j'ai des chiffres différents. Je ne comprends pas ce qui se passe? Est-ce que quelqu'un voit quelque chose de mal avec mon algorithme? Il faut que ce soit quelque chose d'évident ...Chiffre de contrôle USS ACS Keyline

La documentation de la méthode peut être trouvée à la page 12-13 de ce document: http://www.usps.com/cpim/ftp/pubs/pub8a.pdf

L'exemple d'application est disponible à: http://ribbs.usps.gov/acs/documents/tech_guides/KEYLINE.EXE

S'IL VOUS PLAÎT NOTE: J'ai corrigé le code ci-dessous, basé sur l'aide des utilisateurs du forum. Ceci afin que les futurs lecteurs puissent utiliser le code dans son intégralité.

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 = '' 
    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 

Répondre

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

DUH! Je savais que j'avais quelque chose en arrière :) Merci! – Jasmine

0

Pourquoi nous avons un mod supplémentaire:

convert (varchar, 10% < < -

Le document indique que seul le dernier chiffre doit être soustrait? 10. Ai-je manqué quelque chose?

+0

Le mod supplémentaire 10 est donc je me retrouve avec seulement le chiffre le plus à droite. – Jasmine

1

Je ne sais pas pourquoi vous jouez avec le des représentations de chaînes entières lorsque vous travaillez dans un langage basé sur un ensemble.

Je ferais probablement comme ci-dessous. J'ai couru quatre tests à travers et ils ont tous réussi. Vous pouvez également étendre cette fonction pour gérer les caractères et vous pouvez même rendre la table permanente si vous le souhaitez vraiment.

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 
+0

Eh bien, j'ai fait une implémentation explicite parce que je veux que cela soit compréhensible pour les programmeurs dans le futur, et personne dans cette boutique ne parle SQL. De plus, quand j'ai fait la même chose que vous, ça n'a pas marché. Je vais essayer votre idée plus tard aujourd'hui et vous faire savoir si cela fonctionne. Merci! – Jasmine

Questions connexes