1. ホーム
  2. mysql

[解決済み】MySQLを使用してランダムでユニークな8文字の文字列を生成する方法

2022-01-26 19:38:50

質問

乗り物が登場するゲームを制作しています。車両に関するデータを含む "vehicles" という MySQL テーブルがあり、車両のライセンスプレートを格納する "plate" というカラムがあります。

さて、ここからは私が困っている部分です。新しい車両を作成する前に、未使用のナンバープレートを見つける必要があるのですが、それは英数字の8文字のランダムな文字列である必要があります。私はこれを実現するために、私がプログラミングしている言語であるLuaでwhileループを使って文字列を生成し、それが使用されているかどうかDBに問い合わせました。しかし、車の台数が増えてくると、これは今以上に非効率になることが予想されます。そこで、MySQLのクエリを使ってこの問題を解決してみることにしました。

必要なクエリーは、テーブルにない8文字の英数字の文字列を生成するだけでよいのです。私は再びgenerate&checkループのアプローチを考えましたが、より効率的なものがある場合に備えて、この質問をそれに限定するものではありません。私は、許容されるすべての文字を含む文字列を定義し、それをランダムに部分文字列化することによって文字列を生成することができましたが、それ以上のものはありません。

どんなことでもご相談ください。

解決方法は?

この問題は、全く異なる2つのサブ問題から構成されています。

  • 文字列は一見ランダムに見える必要がある
  • 文字列は一意でなければならない

ランダム性は非常に簡単に実現できますが、リトライ・ループを使わない一意性はそうではありません。そこで、まず一意性に注目することにします。非ランダムな一意性を実現するためには AUTO_INCREMENT . ですから、一意性を保持する擬似ランダム変換を使っても問題ないでしょう。

  • ハッシュは @paul から提案されました。
  • AES-encryptも適合します。
  • でも、いいものがあるんですよ。 RAND(N) そのものです!

同じ種で作られた乱数列は、次のように保証されます。

  • 再現性がある
  • 最初の8回の繰り返しで異なる
  • シードが INT32

そこで、@AndreyVolkや@GordonLinoffのアプローチを使うのですが、その際に シード RAND :

例:アスミン idAUTO_INCREMENT カラムになります。

INSERT INTO vehicles VALUES (blah); -- leaving out the number plate
SELECT @lid:=LAST_INSERT_ID();
UPDATE vehicles SET numberplate=concat(
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@lid)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed:=round(rand(@seed)*4294967296))*36+1, 1),
  substring('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', rand(@seed)*36+1, 1)
)
WHERE id=@lid;