PostgresQL 的 Verhoeff 校验和函数

Verhoeff Checksum function for PostgresSQL

我在以下位置找到了 PostgresSQL 的 Verhoeff 校验和函数:https://github.com/HIISORG/SNOMED-CT-PostgreSQL/blob/master/Verhoeff.sql

CREATE OR REPLACE FUNCTION verhoeff_generate (
  input numeric = NULL::numeric
)
RETURNS smallint AS $$
DECLARE
  _c SMALLINT := 0;
  _m SMALLINT;
  _i SMALLINT := 0;
  _n VARCHAR(255);
  -- Delcare array
  _d CHAR(100) := '0123456789123406789523401789563401289567401239567859876043216598710432765982104387659321049876543210';
  _p CHAR(80) := '01234567891576283094580379614289160435279453126870428657390127938064157046913258';
  _v CHAR(10) := '0432156789';
BEGIN
  _n := REVERSE(input::TEXT);
  WHILE _i<length(_n) LOOP
    _m := CAST(SUBSTRING(_p,(((_i + 1)%8)*10) + CAST(SUBSTRING(_n, _i+1, 1) AS SMALLINT) + 1, 1) AS SMALLINT);

    _c := CAST (substring(_d, (_c *10 + _m + 1), 1) AS SMALLINT);
    _i := _i + 1;
  END LOOP;

  RETURN CONCAT(input, CAST(substring(_v,_c+1,1) as SMALLINT));
END; $$
LANGUAGE 'plpgsql'
IMMUTABLE
RETURNS NULL ON NULL INPUT;

我修改了 RETURN,以便它将 INPUT 与校验和数字连接起来:

RETURN CONCAT(input, CAST(substring(_v,_c+1,1) as SMALLINT));

我得到错误:

[2020-02-20 11:53:19] [22003] ERROR: value "331010000014" is out of range for type smallint
[2020-02-20 11:53:19] Where: PL/pgSQL function verhoeff_generate(numeric) while casting return value to function's return type

我试过:

 RETURN CONCAT(input, CAST(substring(_v,_c+1,1) as BIGINT));

仍然出现同样的错误。

您已经修改了提供 return 值的代码,从 returning 原来的 smallint 改为现在的字符串。 (CONCAT 函数输出一个字符串 - 在将数字输入 concat 之前,您可以任意多次转换数字,但它们将被转换为字符串,然后连接起来,并且concat 输出一个字符串,不管你输入什么)。

CONCAT 现在 return 给你一个包含太多数字的字符串(它的数字太大)以适应 smallint - PG 试图隐式地为你执行的转换。这代表核心问题:

CREATE OR REPLACE FUNCTION return_big_number ()
RETURNS smallint AS $$
  RETURN '32769'; --string of a number that is too big for a smallint
END; $$

'32769' 是一个无法转换为 smallint 的字符串,因为它在数值上太大了 - smallint 的上限为 32767。同样,通过使用 concat,您将生成一个包含代表 a 的数字的字符串对于 smallint

来说数字太大

要么更改顶部的函数声明,使其return成为合适的字符串:

RETURNS smallint AS $$
        ^^^^^^^^
       change this to perhaps "RETURNS text AS $$"

或者,如果将输出作为数字输出更适合您,请更改函数,使其声明为 return 可以表示比 smallint 更多数字的数字数据类型,然后更改 return 值计算以保持其数字(将输入乘以 10 的某个幂,然后添加校验和,而不是将输入更改为字符串并连接校验和)