これは、plpgsql で既に実装されている衝突のない優れた方法です。
最初のステップ: PG wikiのpseudo_encrypt関数を検討してください。この関数は引数として 32 ビット整数を取り、人間の目にはランダムに見えますが、その引数に一意に対応する 32 ビット整数を返します (つまり、ハッシュではなく暗号化です)。関数内で式を変更することができます: [0..1] の範囲で結果を生成する、あなただけが知っ(((1366.0 * r1 + 150889) % 714025) / 714025.0)
ている別の関数を使用します (定数を微調整するだけでおそらく十分です。以下の私の試みを参照してください) . より理論的な説明については、 Feistel サイファーに関するウィキペディアの記事を参照してください。
2 番目のステップ: 選択したアルファベットで出力番号をエンコードします。これは、すべての英数字を使用して base 62 で実行する関数です。
CREATE OR REPLACE FUNCTION stringify_bigint(n bigint) RETURNS text
LANGUAGE plpgsql IMMUTABLE STRICT AS $$
DECLARE
alphabet text:='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
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 output;
END $$
ここで、単調なシーケンスに対応する最初の 10 個の URL について得られるものを次に示します。
select stringify_bigint(pseudo_encrypt(i)) from generate_series(1,10) as i;
stringify_bigint
------------------
tWJbwb
eDUHNb
0k3W4b
w9dtmc
wWoCi
2hVQz
PyOoR
cjzW8
ビゴクブ
A5tDHb
結果はランダムに見え、出力空間全体で一意であることが保証されます (入力空間全体を負の整数で使用する場合、2^32 または約 40 億の値)。40 億の値が十分に広くない場合は、2 つの 32 ビットの結果を慎重に組み合わせて、出力の単一性を失わずに 64 ビットにすることができます。注意が必要な部分は、符号ビットを正しく処理し、オーバーフローを回避することです。
関数を変更して独自の独自の結果を生成する方法について: 関数本体で定数を 1366.0 から 1367.0 に変更し、上記のテストを再試行してみましょう。結果がどのように完全に異なるかを確認してください。
NprBxb
SY38Ob
urrF6b
OjKVnc
vdS7j
UEFEB
3zuaT
0fjsab
j7OYrb
PYiwJb
更新: C 拡張機能をコンパイルできる人にとって、 の適切な代替品pseudo_encrypt()
はrange_encrypt_element()
からのpermuteseq extension
もので、次の利点があります。