2009-02-19 39 views
0

我已經使用SQL實現了「MOD 10」校驗位算法,根據其文檔中的方法爲美國郵政服務地址更改服務Keyline,但似乎我得到了錯誤的數字!我們的輸入字符串中只有數字,使計算更容易一些。當我將結果與測試應用程序的結果進行比較時,我得到的數字不同。我不明白髮生了什麼事?有沒有人看到我的算法有什麼問題?它一定是明顯的東西...USPS ACS Keyline Check Digit

該方法的文檔,可以在這個文件的12-13頁上找到: http://ribbs.usps.gov/acs/documents/tech_guides/KEYLINE.EXE

http://www.usps.com/cpim/ftp/pubs/pub8a.pdf

示例應用程序可以在這裏找到請注意:我根據論壇用戶的幫助修復了下面的代碼。這是爲了讓未來的讀者能夠完整地使用這些代碼。

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 

回答

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

DUH!我知道我有東西倒退:) 謝謝! – Jasmine 2009-02-19 20:02:10

0

爲什麼我們有一個額外的國防部:

轉換(VARCHAR,10% < < -

文件稱,只有最後一個數字需要從扣除? 10.我錯過了什麼嗎?

+0

額外的mod 10是我最後只有最右邊的數字。 – Jasmine 2009-02-19 19:45:14

1

我不確定你爲什麼搞亂當你使用基於集合的語言工作時,整個字符串表示。

我可能會像下面這樣做。我跑了四次測試,他們都成功了。如果你真的想這麼做,你可以很容易地擴展這個角色來處理角色,甚至可以讓表格永久化。

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

那麼,我做了一個明確的實現,因爲我希望將來它對程序員是可以理解的,而且這個商店裏沒有人會說SQL。另外,當我做了類似的事情時,它不起作用。將在今天晚些時候嘗試你的想法,並告訴你它是否有效。謝謝! – Jasmine 2009-02-19 19:46:40