Saya sedang mengerjakan game yang melibatkan kendaraan di beberapa titik. Saya memiliki tabel MySQL bernama "kendaraan" yang berisi data tentang kendaraan, termasuk kolom "pelat" yang menyimpan Plat untuk kendaraan tersebut.
Sekarang inilah bagian yang bermasalah dengan saya. Saya perlu menemukan pelat nomor yang tidak digunakan sebelum membuat kendaraan baru - itu harus berupa string acak 8 karakter alfanumerik. Bagaimana saya mencapai ini adalah menggunakan while loop di Lua, yang merupakan bahasa pemrograman saya, untuk menghasilkan string dan query DB untuk melihat apakah itu digunakan. Namun, seiring bertambahnya jumlah kendaraan, saya perkirakan ini akan menjadi semakin tidak efisien seperti sekarang. Oleh karena itu, saya memutuskan untuk mencoba dan memecahkan masalah ini menggunakan kueri MySQL.
Kueri yang saya butuhkan seharusnya hanya menghasilkan string alfanumerik 8 karakter yang belum ada dalam tabel. Saya memikirkan pendekatan generate & check loop lagi, tetapi saya tidak membatasi pertanyaan ini hanya untuk berjaga-jaga jika ada pertanyaan yang lebih efisien. Saya telah dapat menghasilkan string dengan mendefinisikan string yang berisi semua karakter yang diizinkan dan secara acak melakukan substring, dan tidak lebih.
Bantuan apa pun dihargai.
Jawaban:
Masalah ini terdiri dari dua sub-masalah yang sangat berbeda:
Meskipun keacakan cukup mudah dicapai, keunikan tanpa retry loop tidak. Ini membawa kita untuk berkonsentrasi pada keunikan terlebih dahulu. Keunikan non-acak bisa dengan mudah dicapai dengan
AUTO_INCREMENT
. Jadi menggunakan transformasi pseudo-random yang menjaga keunikan akan baik-baik saja:RAND(N)
sendiri!Urutan nomor acak yang dibuat oleh benih yang sama dijamin akan ada
INT32
Jadi kami menggunakan pendekatan @ AndreyVolk atau @ GordonLinoff, tetapi dengan seeded
RAND
:misalnya Assumin
id
adalahAUTO_INCREMENT
kolom:sumber
RAND(LAST_INSERT_ID()); UPDATE vehicles (...) , rand()*36+1, (...)
(atau mengembalikan 8 kali karakter yang sama). Bagaimana kita bisa yakin bahwa 8 panggilan berurutan kerand()
dijamin mengembalikan urutan yang berbeda jika dijalankan dengan seed yang berbeda?FLOOR()
sekitar parameter substring kedua:…
substring('ABC … 789', floor(rand(@seed:= … )*36+1), 1),
…
Pada beberapa kesempatan, substring mencoba memilih karakter 36.9, yang bila dibulatkan ke 37, tidak akan menghasilkan karakter yang dipilih.floor()
. Sqlfiddle ini menunjukkan, bahwa duplikat dibuat untuk string sepanjang tiga karakter.193844
dan775771
algoritma Anda akan menghasilkan string yang samaT82X711
( demo ).Seperti yang saya nyatakan dalam komentar saya, saya tidak akan peduli dengan kemungkinan tabrakan. Buat saja string acak dan periksa apakah ada. Jika ya, coba lagi dan Anda tidak perlu melakukannya lebih dari beberapa kali kecuali Anda telah menetapkan sejumlah besar piring.
Solusi lain untuk menghasilkan string pseudo-random sepanjang 8 karakter dalam SQL murni (Saya):
Anda dapat mencoba yang berikut (pseudo-code):
Karena posting ini telah menerima tingkat perhatian yang tidak terduga, izinkan saya menyoroti komentar ADTC : potongan kode di atas cukup bodoh dan menghasilkan digit berurutan.
Untuk keacakan yang tidak terlalu bodoh, cobalah sesuatu seperti ini:
Dan untuk keacakan yang benar (aman secara kriptograpik), gunakan
RANDOM_BYTES()
daripadaRAND()
(tetapi kemudian saya akan mempertimbangkan untuk memindahkan logika ini ke lapisan aplikasi).sumber
9
kode AndaSELECT LEFT(UUID(), 9);
, selalu ada-
di akhir string yang dihasilkan sebagai karakter kesembilan. Itu konstan. Mengapa?SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
Bagaimana dengan menghitung hash MD5 (atau lainnya) dari bilangan bulat berurutan, lalu mengambil 8 karakter pertama.
yaitu
dll.
peringatan: Saya tidak tahu berapa banyak yang dapat Anda alokasikan sebelum tabrakan (tetapi itu akan menjadi nilai yang diketahui dan konstan).
sunting: Sekarang ini adalah jawaban lama, tetapi saya melihatnya lagi dengan waktu di tangan saya, jadi, dari pengamatan ...
Peluang semua angka = 2,35%
Peluang semua huruf = 0,05%
Tabrakan pertama saat MD5 (82945) = "7b763dcb ..." (hasil yang sama seperti MD5 (25302))
sumber
Buat string acak
Berikut adalah fungsi MySQL untuk membuat string acak dengan panjang tertentu.
Pemakaian
SELECT RANDSTRING(8)
untuk mengembalikan string 8 karakter.Anda dapat menyesuaikan file
@allowedChars
.Keunikan tidak dijamin - seperti yang akan Anda lihat di komentar untuk solusi lain, ini tidak mungkin. Sebagai gantinya Anda harus membuat string, periksa apakah sudah digunakan, dan coba lagi jika sudah digunakan.
Periksa apakah string acak sudah digunakan
Jika kita ingin menyimpan kode pemeriksaan tabrakan dari aplikasi, kita dapat membuat pemicu:
sumber
Berikut salah satu caranya, menggunakan alfa numerik sebagai karakter yang valid:
Perhatikan bahwa tidak ada jaminan keunikan. Anda harus memeriksanya secara terpisah.
sumber
Berikut metode lain untuk menghasilkan string acak:
SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8) AS myrandomstring
sumber
Anda dapat menggunakan fungsi rand () dan char () MySQL :
sumber
Anda dapat membuat string alfanumerik acak dengan:
Anda dapat menggunakannya di
BEFORE INSERT
pemicu dan memeriksa duplikat di loop sementara:Sekarang masukkan saja data Anda seperti
Dan pemicunya akan menghasilkan nilai untuk
plate
kolom tersebut.( demo sqlfiddle )
Itu berfungsi seperti ini jika kolom memungkinkan NULLs. Jika Anda menginginkannya NOT NULL Anda perlu menentukan nilai default
Anda juga dapat menggunakan algoritme penghasil string acak lainnya di pemicu jika huruf besar alfanumerik bukan yang Anda inginkan. Tapi pemicunya akan menjaga keunikan.
sumber
pow(36,8)-1
adalah representasi numerik dariZZZZZZZZ
. Jadi kami menghasilkan bilangan bulat acak antara0
dan '36 ^ 8-1 '(dari0
ke2821109907455
) dan mengubahnya menjadi string alfanumerik antara0
danZZZZZZZZ
unsingconv()
. lapad () akan mengisi string dengan angka nol hingga memiliki panjang 8.conv()
hanya mendukung basis hingga 36 (10 digit + 26 huruf besar). Jika Anda ingin memasukkan huruf kecil, Anda memerlukan cara lain untuk mengubah angka menjadi string.Untuk menghasilkan string acak, Anda dapat menggunakan:
SUBSTRING(MD5(RAND()) FROM 1 FOR 8)
Anda menerima sesuatu seperti itu:
353E50CC
sumber
Untuk String yang terdiri dari 8 angka acak dan huruf besar dan kecil, inilah solusi saya:
Dijelaskan dari dalam ke luar:
RAND
menghasilkan angka acak antara 0 dan 1MD5
menghitung jumlah MD5 dari (1), 32 karakter dari af dan 0-9UNHEX
menerjemahkan (2) menjadi 16 byte dengan nilai dari 00 ke FFTO_BASE64
menyandikan (3) sebagai base64, 22 karakter dari az dan AZ dan 0-9 plus "/" dan "+", diikuti oleh dua "="REPLACE
menghapus karakter "/", "+" dan "=" dari (4)LEFT
mengambil 8 karakter pertama dari (5), ubah 8 menjadi yang lain jika Anda membutuhkan lebih banyak atau lebih sedikit karakter dalam string acak AndaLPAD
menyisipkan nol di awal (6) jika kurang dari 8 karakter; sekali lagi, ubah 8 ke sesuatu yang lain jika perlusumber
I Menggunakan data dari kolom lain untuk menghasilkan "hash" atau string unik
sumber
8 huruf dari alfabet - Semua huruf besar:
sumber
Jika Anda tidak memiliki id atau seed, seperti itu untuk daftar nilai di sisipkan:
sumber
Solusi sederhana dan efisien untuk mendapatkan string 10 karakter acak dengan huruf besar dan kecil serta angka:
sumber
Jika Anda setuju dengan pelat nomor "acak" tetapi sepenuhnya dapat diprediksi, Anda dapat menggunakan register geser umpan balik linier untuk memilih nomor pelat berikutnya - dijamin untuk melewati setiap nomor sebelum mengulang. Namun, tanpa matematika yang rumit, Anda tidak akan dapat melewati setiap string alfanumerik 8 karakter (Anda akan mendapatkan 2 ^ 41 dari 36 ^ 8 (78%) kemungkinan pelat). Untuk membuat ini mengisi ruang Anda lebih baik, Anda bisa mengecualikan surat dari piring (mungkin O), memberi Anda 97%.
sumber
Dengan mempertimbangkan jumlah karakter yang Anda butuhkan, Anda akan memiliki peluang yang sangat kecil untuk menghasilkan dua pelat nomor yang persis sama. Jadi Anda mungkin bisa lolos dengan menghasilkan angka-angka di LUA.
Anda memiliki 36 ^ 8 pelat nomor unik yang berbeda (2.821.109.907.456, itu banyak), bahkan jika Anda sudah memiliki satu juta pelat nomor, Anda akan memiliki peluang yang sangat kecil untuk menghasilkan yang sudah Anda miliki, sekitar 0,000035%
Tentu saja, itu semua tergantung pada berapa banyak pelat nomor yang akan Anda buat.
sumber
Fungsi ini menghasilkan string acak berdasarkan panjang input Anda dan karakter yang diizinkan seperti ini:
kode fungsi:
Kode ini didasarkan pada fungsi string acak yang dikirim oleh "Ross Smith II"
sumber
Untuk membuat 10 digit alfanumerik acak , tidak termasuk karakter yang mirip 01oOlI:
Inilah yang saya butuhkan untuk membuat kode voucher . Karakter yang membingungkan dihapus untuk mengurangi kesalahan saat mengetiknya ke dalam formulir kode voucher.
Semoga ini bisa membantu seseorang, berdasarkan jawaban brilian Jan Uhlig .
Silakan lihat jawaban Jan untuk rincian tentang cara kerja kode ini.
sumber
Gunakan prosedur tersimpan ini dan gunakan setiap saat
sumber
Cara mudah yang menghasilkan nomor unik
sumber
Hasilkan 8 karakter kunci
sumber
Saya mencari sesuatu yang serupa dan saya memutuskan untuk membuat versi saya sendiri di mana Anda juga dapat menentukan benih yang berbeda jika diinginkan (daftar karakter) sebagai parameter:
Dapat digunakan sebagai:
Yang akan menggunakan benih bawaan dari karakter huruf besar dan kecil + digit. NULL juga akan menjadi nilai, bukan ''.
Tetapi seseorang dapat menentukan benih khusus saat memanggil:
sumber