You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL GTIN校验函数异常:计算校验码与实际不符求助

14位GTIN校验函数计算错误问题

我使用以下PostgreSQL函数验证14位GTIN编码,但未得到预期结果:

CREATE OR REPLACE FUNCTION bulk_loader.is_valid_gtin_check_digit(gtin text)
    RETURNS boolean
    LANGUAGE plpgsql
    IMMUTABLE STRICT LEAKPROOF
AS $function$
DECLARE
    gtin_length integer;
    check_digit integer;
    gtin_without_check_digit text;
    gtin_reverse text;
    gtin_digits integer[];
    i integer;
    sum integer := 0;
    computed_check_digit integer := 0;
BEGIN
    gtin := regexp_replace(gtin, '\D', '', 'g');
    gtin_length := length(gtin);

    -- If the GTIN code doesn't have 14 digits, return false
    IF gtin_length <> 14 THEN
        RETURN FALSE;
    END IF;

    gtin_without_check_digit := left(gtin, gtin_length - 2);
    check_digit := cast(right(gtin, 1) as integer);

    -- Check if gtin_without_check_digit consists of exactly 13 numeric digits
    IF gtin_without_check_digit ~ '^[0-9]{13}$' THEN
        gtin_reverse := reverse(gtin_without_check_digit);
        gtin_digits := string_to_array(gtin_reverse, NULL)::int[];

        -- Compute the check digit
        FOR i IN 1..array_upper(gtin_digits, 1) LOOP
            sum := sum + gtin_digits[i] * CASE i % 2 WHEN 0 THEN 3 ELSE 1 END;
        END LOOP;
        computed_check_digit := (10 - sum % 10) % 10;

        -- Compare the computed check digit with the last digit of the GTIN code
        RETURN computed_check_digit = check_digit;
    END IF;

    RETURN FALSE;
EXCEPTION WHEN others THEN
    RETURN FALSE;
END;
$function$;

执行语句:

select is_valid_gtin_check_digit('10628176957012');

此时计算出的校验码computed_check_digit为9,而实际传入的GTIN最后一位校验码为2,我预期计算值应为2。使用的PostgreSQL版本为9.6.3 on x86_64-pc-linux-gnu。


错误原因及修正方案

原函数存在两个关键错误:

  • 数据位截取错误
    原代码中gtin_without_check_digit := left(gtin, gtin_length - 2);错误地截取了前12位,而14位GTIN的校验计算需要基于前13位(去掉最后1位校验码),应改为:

    gtin_without_check_digit := left(gtin, gtin_length - 1);
    
  • 权重计算逻辑错误
    根据GS1的GTIN校验规则,需从右往左(不含校验码)对奇数位数字乘3、偶数位数字乘1。原函数反转数据位后,对偶数位乘3,与规则相反,应调整CASE条件:

    sum := sum + gtin_digits[i] * CASE i % 2 WHEN 1 THEN 3 ELSE 1 END;
    

修正后的完整函数

CREATE OR REPLACE FUNCTION bulk_loader.is_valid_gtin_check_digit(gtin text)
    RETURNS boolean
    LANGUAGE plpgsql
    IMMUTABLE STRICT LEAKPROOF
AS $function$
DECLARE
    gtin_length integer;
    check_digit integer;
    gtin_without_check_digit text;
    gtin_reverse text;
    gtin_digits integer[];
    i integer;
    sum integer := 0;
    computed_check_digit integer := 0;
BEGIN
    gtin := regexp_replace(gtin, '\D', '', 'g');
    gtin_length := length(gtin);

    -- 校验GTIN长度是否为14位
    IF gtin_length <> 14 THEN
        RETURN FALSE;
    END IF;

    -- 截取前13位(去掉最后1位校验码)
    gtin_without_check_digit := left(gtin, gtin_length - 1);
    check_digit := cast(right(gtin, 1) as integer);

    -- 验证前13位是否全为数字
    IF gtin_without_check_digit ~ '^[0-9]{13}$' THEN
        gtin_reverse := reverse(gtin_without_check_digit);
        gtin_digits := string_to_array(gtin_reverse, NULL)::int[];

        -- 计算校验码:反转后奇数位乘3,偶数位乘1(对应原数据位从右往左的奇数位乘3)
        FOR i IN 1..array_upper(gtin_digits, 1) LOOP
            sum := sum + gtin_digits[i] * CASE i % 2 WHEN 1 THEN 3 ELSE 1 END;
        END LOOP;
        computed_check_digit := (10 - sum % 10) % 10;

        RETURN computed_check_digit = check_digit;
    END IF;

    RETURN FALSE;
EXCEPTION WHEN others THEN
    RETURN FALSE;
END;
$function$;

说明

通过GS1官方规则验证,1062817695701对应的正确校验码为9,因此原传入的GTIN10628176957012本身是无效的,修正后的函数返回false是符合规则的结果。若需验证有效GTIN,可使用10628176957019,函数会返回true。

内容的提问来源于stack exchange,提问作者Matias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 16:49:56