我有一个 char 字段,其默认值应该是 ksuid。如何在 postgres 中生成 ksuid?
3 回答
3
我建议您最好的选择是创建一个用户域。然后定义一个函数来生成你的 ksuid。然后将域更改为默认使用此功能。需要时将您的列定义为该 DOMAIN 类型。
-- setup domain and the generating function
create domain ksuid character varying(27);
create or replace function generate_ksuid()
returns ksuid
language sql
as $$
select substring(
replace(to_char(clock_timestamp(),'yyyymmddhh24missus')
|| (to_char(random()*1e9,'000000000')
),' ',''),1,27)::ksuid;
$$;
alter domain ksuid set default generate_ksuid();
在此处查看完整示例,包括使用。当然,函数 generate_ksuid 需要根据您的要求进行调整。该示例仅基于 clock_timestamp 和一个随机数。
于 2020-07-29T16:01:00.980 回答
0
此函数在 PostgreSQL 上生成 KSUID。它使用numeric数据类型将时间和有效负载转换为 base62。
该函数生成的 KSUID 与参考实现兼容。
/**
* Returns a Segment's KSUID.
*
* Reference implementation: https://github.com/segmentio/ksuid
* Also read: https://segment.com/blog/a-brief-history-of-the-uuid/
*/
create or replace function fn_ksuid() returns text as $$
declare
v_time timestamp with time zone := null;
v_seconds numeric := null;
v_payload bytea := null;
v_numeric numeric := null;
v_base62 text := '';
v_epoch numeric = 1400000000; -- 2014-05-13T16:53:20Z
v_alphabet char array[62] := array[
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'];
i integer := 0;
begin
-- Get the current time
v_time := clock_timestamp();
-- Extract seconds from the current time and apply epoch
v_seconds := EXTRACT(EPOCH FROM v_time) - v_epoch;
-- Generate a numeric value from the seconds
v_numeric := v_seconds * pow(2::numeric, 128);
-- Generate a pseudo-random payload
v_payload := decode(md5(v_time::text || random()::text || random()::text), 'hex');
-- Add the payload to the numeric value
while i < 16 loop
i := i + 1;
v_numeric := v_numeric + (get_byte(v_payload, i - 1) * pow(2::numeric, (16 - i) * 8));
end loop;
-- Encode the numeric value to base62
while v_numeric <> 0 loop
v_base62 := v_base62 || v_alphabet[mod(v_numeric, 62) + 1];
v_numeric := div(v_numeric, 62);
end loop;
v_base62 := reverse(v_base62);
v_base62 := lpad(v_base62, 27, '0');
return v_base62;
end $$ language plpgsql;
链接到GitHub Gist。
于 2022-01-09T15:45:50.873 回答
0
我想建议对 fabiolimace 的解决方案稍作改动。反而:
v_payload := decode(md5(v_time::text || random()::text || random()::text), 'hex');
使用更强大的功能gen_random_bytes():
v_payload := gen_random_bytes(16);
它需要pgcrypto启用扩展:
CREATE EXTENSION pgcrypto;
于 2022-02-16T06:30:37.610 回答