Postgresql

如何在 PostgreSQL 中觸發/返回這個生成器函式?

  • May 28, 2017

我正在為各種類別的使用者提供一個密鑰表,因此我正在考慮如何使用每個SELECT. 生成速記唯一 ID 的函式

  1. 執行緒回答生成人類可讀/可用、簡短但唯一的 ID,但沒有鹽,所以沒有。
  2. http://hashids.org/可以是此處答案提出的有效選項
  3. 任何預設的 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_idSELECT * 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 | 富

在此範例中,表中同時存在idshort_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在這裡

引用自:https://dba.stackexchange.com/questions/174771