如何在 PostgreSQL 中觸發/返回這個生成器函式?
我正在為各種類別的使用者提供一個密鑰表,因此我正在考慮如何使用每個
SELECT
. 生成速記唯一 ID 的函式
- 執行緒回答生成人類可讀/可用、簡短但唯一的 ID,但沒有鹽,所以沒有。
- http://hashids.org/可以是此處答案提出的有效選項
- 任何預設的 PostgreSQL 選項?
我需要密鑰的密鑰表範例
Module 1 1. <key1> 2. <key2> 3. ... Module 2 1. <key1> 2. <key2>
鍵綁定到表中的 SERIAL 主鍵
event_log
。我正在考慮數據庫是否可以為您完成生成任務,即如何將您的主鍵綁定到任何可以生成這種速記形式的算法。我目前在表格中的數據如下,SERIAL PRIMARY
不太清楚CREATE TABLE event_log ( data_id SERIAL PRIMARY KEY NOT NULL, name VARCHAR(10) NOT NULL, module INTEGER NOT NULL, - - 1 or 2 or 3 as value time TIMESTAMP NOT NULL );
想法:綁定一個
TRIGGER
和/RETURNING nice_id
或SELECT * FROM event_log WHERE module=1
查詢作業系統:Debian Linux 8.7
SQL:PostgreSQL 9.4 和/或 R sqldf
我在想數據庫是否可以為您完成生成任務,即如何將您的主鍵綁定到任何可以生成這種速記形式的算法
既然您提到了鹽,我假設您正在尋找外人難以猜測或複制的短字元串,儘管它起源於數據庫序列。permuteseq擴展基本上就是這樣做的。
必須提供從整數生成短字元串的函式,例如:
CREATE FUNCTION id_to_alpha(n int) RETURNS text LANGUAGE plpgsql IMMUTABLE STRICT AS $$ DECLARE alphabet text:='abcdefghijklmnopqrstuvwxyz012345678'; sign_char char:='9'; base int:=length(alphabet); _n bigint:=abs(n); output text:=''; BEGIN LOOP output := output || substr(alphabet, 1+(_n%base)::int, 1); _n := _n / base; EXIT WHEN _n=0; END LOOP; RETURN CASE WHEN (n<0) THEN output || sign_char::text ELSE output END; RETURN output; END; $$;
然後您可以在 BEFORE INSERT 觸發器中設置短 id slug,如下所示:
CREATE EXTENSION permuteseq; CREATE TABLE things( id serial, short_id text, name varchar(10) not null ); -- keep the sequence short for short output strings ALTER SEQUENCE things_id_seq MAXVALUE 1000000; CREATE FUNCTION generate_short_id() RETURNS TRIGGER AS $$ DECLARE secret bigint := 123456789; -- change for a different secret sequence BEGIN NEW.short_id := id_to_alpha(range_encrypt_element(NEW.id, 1, 10000000, secret)::int); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER things_trigger BEFORE INSERT ON things FOR EACH ROW EXECUTE PROCEDURE generate_short_id();
測試它:
INSERT INTO things(name) SELECT 'foo' FROM generate_series(1,10); SELECT * FROM things;
編號 | 短ID | 姓名 ----+----------+------ 1 | wf3hg | 富 2 | tm6lg | 富 3 | riqbg | 富 4 | p6jp | 富 5 | h3r3c | 富 6 | 3sx5d | 富 7 | w8ecd | 富 8 | km3le | 富 9 | llt1e | 富 10 | xwtxc | 富
在此範例中,表中同時存在
id
和short_id
,但id
在技術上與 . 是多餘的short_id
。您可以在沒有這樣語法的情況下在表之外創建一個序列SERIAL
,甚至id
在表中也沒有:CREATE SEQUENCE seq_pk MAXVALUE 1000000; CREATE TABLE things2( short_id TEXT DEFAULT id_to_alpha(permute_nextval('seq_pk'::regclass, 123456::bigint)::int) PRIMARY KEY, name text ); INSERT INTO things2(name) values('foo'); SELECT * FROM things2; short_id | name ----------+------ znyh | foo
如果您不能使用
permuteseq
,作為仍然基於加密 ID 的替代方案,您可以查看 SKIP32的 plpgsql 實現,或64 位 (bigint) 的XTEA ,它不需要編譯或成為超級使用者。缺點是您無法通過更改序列的範圍來微調輸出的大小。
您可以只使用
sequence
, base64 編碼結果,並將其用作您的密鑰。這個概念是,給定一個
awful_id
,把它變成對人類來說更容易一些的東西(儘管我們可能不同意是否310276431
比 更容易或更難MzEwMjc2NDMx
):SELECT awful_id, replace(encode(decode(awful_id::text || 'x', 'escape'), 'base64'), '=', '') AS "nicer_id??" FROM generate_series(1, 1000, 13) as s(awful_id) ;
這會產生…
可怕的ID | 更好的ID?? -------: | :--------- 1 | MXg 14 | 港鐵4 27 | Mjd4 40 | NDB4 [...] 第924章 OTI0eA 第937章 OTM3eA 950 | 奧圖韋 第963章 奧泰茲 第976章 OTc2eA 989 | OTg5eA
然後,您將定義沒有序列主鍵但基於序列號的表:
您為需要合成主鍵的每個表創建一個序列:
CREATE SEQUENCE t_sq ;
您根據此序列定義表的 PK,但已編碼:
CREATE TABLE t ( nice_id char(10) PRIMARY KEY DEFAULT replace(encode(decode(nextval('t_sq') || 'x', 'escape'), 'base64'), '=', ''), more_data text ) ;
您可以將數據插入其中,就好像您
nice_id
是一個序列一樣:INSERT INTO t (more_data) VALUES ('a'), ('b'), ('c'), ('d') RETURNING t.* ;
nice_id | 更多數據 :--------- | :-------- MXg | 一種 鎂| b M3g | C 氨水 | d
dbfiddle在這裡