主キーを自動インクリメントして生成したいが、インクリメントを変化させたい。たとえば、増分範囲が100の場合、自動生成されたキーは次のようになります。
-20(1〜100の乱数)
-30(1から100までの乱数10を追加)
-113(1から100までの乱数83を追加)
-118(1から100までの乱数5を追加)
-217(1から100までの乱数99を追加)
-220(1から100までの乱数3を追加)
データドメインはHTTP RESTエンドポイントを介して公開されることがよくあります。エンドユーザーが数値をインクリメントするだけで主キーを推測できないようにしたいと思います。
可能であれば、UUID/GUIDを回避しようとしています。私のREST URLは長く、多くの場合親子の識別子が付いています(はい、それは避けられますが、私はテスト/トラブルシューティングを簡単にするためにそれを好みます)したがって、識別子として数値を好みます。
私が知らないもっと簡単な解決策はありますか?私はPostgreSQLを使用していますが、一般的なソリューションも問題ありません。
あなたの目標は次のとおりです:
エンドユーザーは、単に数値をインクリメントするだけでは主キーを推測できません。
次に、キーの可変増分だけではなく(数十または数百の値を検索する必要があるため)、完全に非線形なものを探してみませんか?
PostgreSQL wikiには、ニーズに合った関数 pseudo_encrypt があります。
順次入力を受け取り、疑似ランダム非反復出力を返します。
通常のSERIAL PRIMARY KEY
の代わりに、次のように展開されます。
CREATE SEQUENCE mytable_colname_seq;
CREATE TABLE mytable (
colname integer PRIMARY KEY DEFAULT nextval('tablename_colname_seq'),
...
);
ALTER SEQUENCE mytable_colname_seq OWNED BY mytable;
代わりに、シーケンスを手動で作成して所有権を割り当て、シーケンスに対して関数を呼び出すDEFAULT
を使用して列を定義できます。例:
DEFAULT pseudo_encrypt(nextval('tablename_colname_id_seq'));
ただし、ここには重要な警告があります。 pseudo_encrypt
関数はテーブルにすでに存在する値を返す可能性があるため、既存のデータがあるテーブルでは、この手法は変更なしでは機能しません。それは繰り返さないことを保証しその自己ですが、テーブルにすでにあるものについては何も知りません。それと一緒にコピーするには、2番目の引数を取るpseudo_encrypt
のバリアントを作成できます。より低いIDを計算した場合は、シーケンスの次の値を使用して計算を繰り返し、そのIDを破棄します。
Craig Ringerは重要な警告に言及しました-既存のデータがあるテーブルの場合、pseudo_encrypt関数はテーブルに既に存在する値を返す可能性があります。 問題を回避するために簡単に変更できる例です :
例はMAX値の場合であり、MIN値は最大の既存の整数IDより大きいことが必要です。
CREATE FUNCTION bounded_pseudo_encrypt(VALUE int, MIN int) returns int AS $$
BEGIN
LOOP
VALUE := pseudo_encrypt_24(VALUE);
EXIT WHEN VALUE >= MIN;
END LOOP;
RETURN VALUE;
END
$$ LANGUAGE plpgsql strict immutable;
パラメータを渡すのではなく、既存の最大の整数IDよりも大きな値をハードコードできます。
CREATE FUNCTION bounded_pseudo_encrypt(VALUE int) returns int AS $$
BEGIN
LOOP
VALUE := pseudo_encrypt_24(VALUE);
EXIT WHEN VALUE >= <hard_coded_integer>;
END LOOP;
RETURN VALUE;
END
$$ LANGUAGE plpgsql strict immutable;