2012-07-27 9 views
22

Chciałbym wygenerować 5-cyfrowy numer, który nie powtórzy się w bazie danych. Powiedz, że mam tabelę o nazwie numbers_mst z polem o nazwie my_number.Jak wygenerować losową liczbę bez powtórzeń w bazie danych za pomocą PHP?

Chcę wygenerować numer tak, jak nie będzie się powtarzać w tym polu my_number. I poprzedzające zera są dozwolone w tym. Zatem liczby takie jak 00001 są dozwolone. Kolejna sprawa to między 00001 a 99999. Jak mogę to zrobić?

Jedną rzeczą, którą mogę zgadnąć, jest to, że mogę utworzyć funkcję rekursywną, aby sprawdzić liczbę w tabeli i wygenerować.

+0

Jeśli poprzedzające zera są dozwolone, czy są one obowiązkowe? Czy 01 różni się od 001? – ChrisW

+0

Potrzebuję 5-cyfrowej liczby lub możesz powiedzieć tylko 5-cyfrowy ciąg znaków. Tak więc nie ma szans na 01 ani 001 :) – aslamdoctor

+0

Co stanie się, gdy zabraknie unikalnych numerów? ;) –

Odpowiedz

37
SELECT FLOOR(RAND() * 99999) AS random_num 
FROM numbers_mst 
WHERE "random_num" NOT IN (SELECT my_number FROM numbers_mst) 
LIMIT 1 

Co to robi:

  1. Wybiera liczbę losową z przedziału od 0 - 1, przy użyciu RAND().
  2. Wzmacnia, która ma być liczbą z zakresu od 0 do 99999.
  3. Wybiera tylko te, które jeszcze nie istnieją w tabeli.
  4. Powoduje wyświetlenie tylko 1 wyniku.
+1

To nie wygląda na prawidłowy sql. Czy to jest? – iWantSimpleLife

+3

To jest poprawne i daje genialną odpowiedź. Czekam, aby dokończyć ograniczenie 2 minut, aby zaakceptować tę odpowiedź: lolz :) – aslamdoctor

+1

Jest mała szansa, że ​​to się nie powiedzie, jeśli tabela numerów nie jest dobrze wypełniona. –

2
  1. Generowanie liczby losowej.

  2. Sprawdź, czy liczba losowa znajduje się w bazie danych.

  3. Jeśli nie, zatrzymaj się, użyj tego numeru.

  4. Przejdź do kroku 1.

2

Masz dwa podejścia:

Pierwszy sugerowane w innych odpowiedzi, jest stworzenie losową liczbę (używając mt_rand()) i sprawdź czy nie ma w bazie danych. Jeśli znajduje się w bazie danych, zarejestruj ponownie i spróbuj ponownie. Jest to najprostsze, jeśli generujesz pojedynczą liczbę - zobacz inne odpowiedzi na kod. Jeśli jednak urzekasz więcej niż 50% liczb, będzie to bardzo powolne i nieefektywne.

Jeśli chcesz mieć wiele liczb, alternatywą jest zapełnienie bazy danych wszystkimi rekordami i kolumna "wybrana". Uruchom zapytanie, aby dowiedzieć się, ile osób nie zostało wybranych, a następnie znajdź losową liczbę z zakresu od 0 do liczby "niewybrane". Następnie uruchom zapytanie SQL, aby uzyskać numer w tej pozycji (jeśli nie został wybrany, użyj LIMIT w mysql) i zaznacz jako wybrane. Nieco zawikłane, to więcej pracy i mniej wydajne, jeśli potrzebujesz tylko kilku liczb, ale będzie o wiele lepiej, jeśli chcesz uzyskać więcej niż 50% (oszacowanie) liczb.

Uwaga: możesz zwiększyć wydajność, przechowując liczbę wybraną lokalnie i uruchamiając kilka mniej zapytań.

+0

Możesz zoptymalizować drugi, po prostu usuwając rekord z tabeli. Przygotuj tabelę z numerami sekwencyjnymi, a następnie po prostu usuń je, gdy wybierzesz je losowo. –

+0

To prawda. Często jednak wydaje mi się, że potrzebuję rekordu, który numer został wybrany, dla którego użytkownika, kampanii, dnia, lub czegoś podobnego. (Mocno wierzę w utrzymywanie logów/śledzenia/śledzenia wszystkiego, a to oznacza, że ​​rzadko usuwam cokolwiek, ale często dodaje się do nich.Dla losowych losowań (gdzie i tak mieszkam) jest to wymóg prawny.Zależy to od pracy.) – Robbie

8

Oprócz odpowiedzi Tushar jest, aby pracować przy numbers_mst jest pusty:

SELECT random_num 
FROM (
    SELECT FLOOR(RAND() * 99999) AS random_num 
    UNION 
    SELECT FLOOR(RAND() * 99999) AS random_num 
) AS numbers_mst_plus_1 
WHERE `random_num` NOT IN (SELECT my_number FROM numbers_mst) 
LIMIT 1 
+1

Poważnie? Dwa i pół roku później? – Areks

+4

Chcę więcej z nich: http://stackoverflow.com/help/badges/17/necromancer?userid=386718 –

+0

Sprawił, że sprawdzam własne odznaki Mam też zbyt lol, dziękuję za odpowiedź. – Sam

3

Jest to najprostszy sposób zbudować unikalny generator kodu bez bazy wyboru, będzie to zaoszczędzić czas wykonania zapytania do bazy danych.

function unique_code_generator($prefix='',$post_fix='') 
    { 
     $t=time(); 
     return (rand(000,111).$prefix.$t.$post_fix); 
    } 

Enjoy, have a nice day kodowania ..

:)

+1

Podoba mi się to, jest to proste, ale jest jedna szansa na 111, że to się nie powiedzie, jeśli zrobi to dwóch użytkowników w tym samym czasie, więc możesz chcieć zwiększyć liczbę losową. :) – Niclas

+0

Tak, zgadzam się z tobą. – Roni

+0

Co stanie się w przypadku problemów z oświetleniem dziennym? –

1

UWAGA: Innego rozwiązania zamieszczone będą działać tylko jeśli kolumna jest skonfigurowany jako NOT NULL. Jeśli NULL, po prostu nie zwróci żadnych wyników. Można rozwiązać kwerendę tak:

SELECT random_num 
FROM (
    SELECT FLOOR(RAND() * 99999) AS random_num 
) AS numbers_mst_plus_1 
WHERE random_num NOT IN (SELECT my_number FROM numbers_mst WHERE my_number IS NOT NULL) 
LIMIT 1 

... The ...WHERE my_number IS NOT NULL jest konieczne!

EDIT: Chciałem tylko wspomnieć, że celowo usuwany wewnętrzną nazwę tabeli SELECT „s, ponieważ nie Seme konieczne i wydawało się przełamać, jeśli nie było żadnych danych w tabeli jeszcze? Być może zostało to celowo uwzględnione? - Proszę wyjaśnić lub skomentować wszystkich, dzięki.

+2

Twoje urządzenie działa dobrze, gdy jest w stanie pobierać losową liczbę, która nie jest używana. Spróbuj jednak małego zestawu danych. Jeśli wybrany rand istnieje, to nic nie zwraca. – jimbob

0

Wiem, że moja odpowiedź jest spóźniona, ale jeśli ktoś szuka tego tematu w przyszłości, kto nie będzie miał losowej liczby z wiodącym zerem, należy dodać funkcję LPAD().

Więc zapytanie spodoba

SELECT LPAD(FLOOR(RAND()*99999),5,0) 

Miłego dnia.

0

Zapytanie folowing generuje cały int od 0 do 99999, znaleźć wartości, które nie są używane w tabeli docelowej i wyjście jednego z tych bezpłatnym numerem losowo:

SELECT random_num FROM (
    select a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) + (10000 * e.a) as random_num 
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a 
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b 
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c 
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d 
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as e 
) q 
WHERE random_num NOT IN(SELECT my_number FROM numbers_mst) 
ORDER BY RAND() LIMIT 1 

Ok, to jest długi, powolny i nie skalowalne, ale działa jako samodzielne zapytanie! Możesz dodać usuń więcej "0" (łączy a, b, c, d, e), aby zwiększyć lub zmniejszyć zasięg.

Można również użyć tego rodzaju techniki generowania wierszy do utworzenia wierszy ze wszystkimi datami, na przykład.

Powiązane problemy