PostgreSQL中将字符串哈希为数值



我需要将存储在数据库中的字符串转换为数值。结果可以是Integer(首选)或Bigint。这个转换将在PL/pgSQL函数的数据库端完成。

有人能给我指一下可以用来实现这一点的算法或任何API吗?

我已经在谷歌上搜索了几个小时了,到目前为止找不到任何有用的东西:(

只保留MD5哈希的前32位或64位。当然,它忽略了md5的主要性质(=碰撞的概率是无穷小的),但你仍然会得到一个广泛的值分散,这可能足以解决你的问题。

SQL函数派生自其他答案:

对于bigint:

create function h_bigint(text) returns bigint as $$
 select ('x'||substr(md5($1),1,16))::bit(64)::bigint;
$$ language sql;

对于int:

create function h_int(text) returns int as $$
 select ('x'||substr(md5($1),1,8))::bit(32)::int;
$$ language sql;

您可以毫无问题地创建md5哈希值:

select md5('hello, world');

这将返回一个带有十六进制数字的字符串。

不幸的是,没有将十六进制转换为整数的内置函数,但当您在PL/pgSQL中这样做时,这可能会有所帮助:

https://stackoverflow.com/a/8316731/330315

PostgreSQL为许多列类型提供了哈希函数。如果需要整数哈希值,可以使用hashtext;如果喜欢bigint哈希值,则可以使用hashtextextended

注意,hashXXXextended函数需要一个额外的种子参数,0表示不使用种子。

在提交信息中,作者Robert Haas说:

以防万一有人想要一个兼容的64位哈希值使用现有的32位哈希值,使当种子为0时,64位哈希值与32位哈希值匹配。

示例

postgres=# SELECT hashtextextended('test string of type text', 0);
   hashtextextended
----------------------
 -6578719834206879717
(1 row)
postgres=# SELECT hashtext('test string of type text');
  hashtext
-------------
 -1790427109
(1 row)

其他数据类型呢

您可以通过检查df hash*的输出来检查后端上所有可用的哈希函数。下面你可以看到PG 14.0中可用的功能。

hanefi=# df hash*
                                     List of functions
   Schema   |           Name           | Result data type |   Argument data types    | Type
------------+--------------------------+------------------+--------------------------+------
 pg_catalog | hash_aclitem             | integer          | aclitem                  | func
 pg_catalog | hash_aclitem_extended    | bigint           | aclitem, bigint          | func
 pg_catalog | hash_array               | integer          | anyarray                 | func
 pg_catalog | hash_array_extended      | bigint           | anyarray, bigint         | func
 pg_catalog | hash_multirange          | integer          | anymultirange            | func
 pg_catalog | hash_multirange_extended | bigint           | anymultirange, bigint    | func
 pg_catalog | hash_numeric             | integer          | numeric                  | func
 pg_catalog | hash_numeric_extended    | bigint           | numeric, bigint          | func
 pg_catalog | hash_range               | integer          | anyrange                 | func
 pg_catalog | hash_range_extended      | bigint           | anyrange, bigint         | func
 pg_catalog | hash_record              | integer          | record                   | func
 pg_catalog | hash_record_extended     | bigint           | record, bigint           | func
 pg_catalog | hashbpchar               | integer          | character                | func
 pg_catalog | hashbpcharextended       | bigint           | character, bigint        | func
 pg_catalog | hashchar                 | integer          | "char"                   | func
 pg_catalog | hashcharextended         | bigint           | "char", bigint           | func
 pg_catalog | hashenum                 | integer          | anyenum                  | func
 pg_catalog | hashenumextended         | bigint           | anyenum, bigint          | func
 pg_catalog | hashfloat4               | integer          | real                     | func
 pg_catalog | hashfloat4extended       | bigint           | real, bigint             | func
 pg_catalog | hashfloat8               | integer          | double precision         | func
 pg_catalog | hashfloat8extended       | bigint           | double precision, bigint | func
 pg_catalog | hashhandler              | index_am_handler | internal                 | func
 pg_catalog | hashinet                 | integer          | inet                     | func
 pg_catalog | hashinetextended         | bigint           | inet, bigint             | func
 pg_catalog | hashint2                 | integer          | smallint                 | func
 pg_catalog | hashint2extended         | bigint           | smallint, bigint         | func
 pg_catalog | hashint4                 | integer          | integer                  | func
 pg_catalog | hashint4extended         | bigint           | integer, bigint          | func
 pg_catalog | hashint8                 | integer          | bigint                   | func
 pg_catalog | hashint8extended         | bigint           | bigint, bigint           | func
 pg_catalog | hashmacaddr              | integer          | macaddr                  | func
 pg_catalog | hashmacaddr8             | integer          | macaddr8                 | func
 pg_catalog | hashmacaddr8extended     | bigint           | macaddr8, bigint         | func
 pg_catalog | hashmacaddrextended      | bigint           | macaddr, bigint          | func
 pg_catalog | hashname                 | integer          | name                     | func
 pg_catalog | hashnameextended         | bigint           | name, bigint             | func
 pg_catalog | hashoid                  | integer          | oid                      | func
 pg_catalog | hashoidextended          | bigint           | oid, bigint              | func
 pg_catalog | hashoidvector            | integer          | oidvector                | func
 pg_catalog | hashoidvectorextended    | bigint           | oidvector, bigint        | func
 pg_catalog | hashtext                 | integer          | text                     | func
 pg_catalog | hashtextextended         | bigint           | text, bigint             | func
 pg_catalog | hashtid                  | integer          | tid                      | func
 pg_catalog | hashtidextended          | bigint           | tid, bigint              | func
 pg_catalog | hashvarlena              | integer          | internal                 | func
 pg_catalog | hashvarlenaextended      | bigint           | internal, bigint         | func
(47 rows)

注意事项

如果你想在不同的系统中有一致的散列,请确保你有相同的排序规则行为。

内置的可整理数据类型为textvarcharchar。如果您有不同的排序规则选项,您可以看到不同的哈希值。例如,与早期版本相比,glibc 2.28(Debian 10,RHEL 8)中翻转的字符串"a-a"one_answers"a+a"的排序顺序。

如果你想在同一台机器上使用散列,你不必担心,只要你不更新glibc或使用不同的排序规则。

更多详细信息,请访问:https://www.citusdata.com/blog/2020/12/12/dont-let-collation-versions-corrupt-your-postgresql-indexes/

必须是整数吗?pg_crypto模块提供了许多标准散列函数(md5、sha1等)。他们都返回字节。我想你可以去掉一些比特,把字节转换成整数。

bigint太小,无法存储加密哈希。Pg支持的最大非字节二进制类型是uuid。你可以向uuid抛出这样的摘要:

select ('{'||encode( substring(digest('foobar','sha256') from 1 for 16), 'hex')||'}')::uuid;
                 uuid                 
--------------------------------------
 c3ab8ff1-3720-e8ad-9047-dd39466b3c89

这是Java的String.hashCode():的实现

CREATE OR REPLACE FUNCTION hashCode(_string text) RETURNS INTEGER AS $$
DECLARE
  val_ CHAR[];
  h_ INTEGER := 0;
  ascii_ INTEGER;
  c_ char;
BEGIN
  val_ = regexp_split_to_array(_string, '');
  FOR i in 1 .. array_length(val_, 1)
  LOOP
    c_ := (val_)[i];
    ascii_ := ascii(c_);
    h_ = 31 * h_ + ascii_;
    raise info '%: % = %', i, c_, h_;
  END LOOP;
RETURN h_;
END;
$$ LANGUAGE plpgsql;

相关内容

  • 没有找到相关文章

最新更新