UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Jeśli następnie wykonam SELECT, widzę, że moja liczba losowa jest identyczna w każdym wierszu . Jakieś pomysły, jak wygenerować unikalne liczby losowe?
sql-server
NibblyPig
źródło
źródło
Jeśli korzystasz z programu SQL Server 2008, możesz również użyć
Co wydaje się nieco prostsze (jest również oceniane raz na wiersz, jak
newid
jest - pokazane poniżej)DECLARE @foo TABLE (col1 FLOAT) INSERT INTO @foo SELECT 1 UNION SELECT 2 UPDATE @foo SET col1 = CRYPT_GEN_RANDOM(2) % 10000 SELECT * FROM @foo
Zwroty (2 losowe prawdopodobnie różne liczby)
col1 ---------------------- 9693 8573
Rozważając niewyjaśnione głosy przeciwne, jedyny uzasadniony powód, jaki przychodzi mi do głowy, jest taki, że ponieważ wygenerowana liczba losowa zawiera się w przedziale 0-65535, co nie jest podzielne równo przez 10000, niektóre liczby będą nieco nadreprezentowane. Sposobem na obejście tego byłoby umieszczenie go w skalarnym UDF, który odrzuca dowolną liczbę powyżej 60 000 i wywołuje się rekurencyjnie, aby uzyskać numer zastępczy.
CREATE FUNCTION dbo.RandomNumber() RETURNS INT AS BEGIN DECLARE @Result INT SET @Result = CRYPT_GEN_RANDOM(2) RETURN CASE WHEN @Result < 60000 OR @@NESTLEVEL = 32 THEN @Result % 10000 ELSE dbo.RandomNumber() END END
źródło
Chociaż uwielbiam używać CHECKSUM, czuję, że lepszym sposobem jest użycie
NEWID()
, tylko dlatego, że nie musisz przechodzić przez skomplikowane obliczenia matematyczne, aby wygenerować proste liczby.Możesz zastąpić
1000
dowolną liczbą, którą chcesz ustawić jako limit, i zawsze możesz użyć znaku plusa, aby utworzyć zakres, powiedzmy, że chcesz losową liczbę od100
do200
, możesz zrobić coś takiego:Łącząc to w swoim zapytaniu:
UPDATE CattleProds SET SheepTherapy= ROUND( 1000 *RAND(convert(varbinary, newid())), 0) WHERE SheepTherapy IS NULL
źródło
Przetestowałem 2 metody randomizacji oparte na zestawach względem RAND (), generując z nich 100 000 000 wierszy. Aby wyrównać pole, wynikiem jest liczba zmiennoprzecinkowa z zakresu 0-1, aby naśladować RAND (). Większość kodu testuje infrastrukturę, więc podsumuję algorytmy tutaj:
-- Try #1 used (CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)%500000000000000000+500000000000000000.0)/1000000000000000000 AS Val -- Try #2 used RAND(Checksum(NewId())) -- and to have a baseline to compare output with I used RAND() -- this required executing 100000000 separate insert statements
Używanie CRYPT_GEN_RANDOM było najwyraźniej najbardziej losowe, ponieważ istnieje tylko 0,000000001% szansy na zobaczenie nawet 1 duplikatu podczas wyrywania 10 ^ 8 liczb Z zestawu 10 ^ 18 liczb. IOW, nie powinniśmy byli widzieć żadnych duplikatów, a ten nie miał żadnego! Wygenerowanie tego zestawu na moim laptopie zajęło 44 sekundy.
Cnt Pct ----- ---- 1 100.000000 --No duplicates
Czas wykonania programu SQL Server: czas procesora = 134795 ms, czas, który upłynął = 39274 ms.
IF OBJECT_ID('tempdb..#T0') IS NOT NULL DROP TABLE #T0; GO WITH L0 AS (SELECT c FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c)) -- 2^4 ,L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B) -- 2^8 ,L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B) -- 2^16 ,L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B) -- 2^32 SELECT TOP 100000000 (CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)%500000000000000000+500000000000000000.0)/1000000000000000000 AS Val INTO #T0 FROM L3; WITH x AS ( SELECT Val,COUNT(*) Cnt FROM #T0 GROUP BY Val ) SELECT x.Cnt,COUNT(*)/(SELECT COUNT(*)/100 FROM #T0) Pct FROM X GROUP BY x.Cnt;
Przy prawie 15 rzędach wielkości mniej losowych ta metoda nie była dwa razy szybsza, a wygenerowanie 100 milionów liczb zajęło tylko 23 sekundy.
Cnt Pct ---- ---- 1 95.450254 -- only 95% unique is absolutely horrible 2 02.222167 -- If this line were the only problem I'd say DON'T USE THIS! 3 00.034582 4 00.000409 -- 409 numbers appeared 4 times 5 00.000006 -- 6 numbers actually appeared 5 times
Czas wykonania programu SQL Server: czas procesora = 77156 ms, czas, który upłynął = 24613 ms.
IF OBJECT_ID('tempdb..#T1') IS NOT NULL DROP TABLE #T1; GO WITH L0 AS (SELECT c FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c)) -- 2^4 ,L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B) -- 2^8 ,L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B) -- 2^16 ,L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B) -- 2^32 SELECT TOP 100000000 RAND(Checksum(NewId())) AS Val INTO #T1 FROM L3; WITH x AS ( SELECT Val,COUNT(*) Cnt FROM #T1 GROUP BY Val ) SELECT x.Cnt,COUNT(*)*1.0/(SELECT COUNT(*)/100 FROM #T1) Pct FROM X GROUP BY x.Cnt;
Samo RAND () jest bezużyteczne do generowania opartego na zestawie, więc wygenerowanie linii bazowej do porównania losowości zajęło ponad 6 godzin i musiało być kilkakrotnie uruchamiane ponownie, aby ostatecznie uzyskać odpowiednią liczbę wierszy wyjściowych. Wydaje się również, że losowość pozostawia wiele do życzenia, chociaż jest lepsza niż użycie sumy kontrolnej (newid ()) do ponownego wpisania każdego wiersza.
Cnt Pct ---- ---- 1 99.768020 2 00.115840 3 00.000100 -- at least there were comparitively few values returned 3 times
Z powodu ponownych uruchomień nie można było zarejestrować czasu wykonania.
IF OBJECT_ID('tempdb..#T2') IS NOT NULL DROP TABLE #T2; GO CREATE TABLE #T2 (Val FLOAT); GO SET NOCOUNT ON; GO INSERT INTO #T2(Val) VALUES(RAND()); GO 100000000 WITH x AS ( SELECT Val,COUNT(*) Cnt FROM #T2 GROUP BY Val ) SELECT x.Cnt,COUNT(*)*1.0/(SELECT COUNT(*)/100 FROM #T2) Pct FROM X GROUP BY x.Cnt;
źródło
require_once('db/connect.php'); //rand(1000000 , 9999999); $products_query = "SELECT id FROM products"; $products_result = mysqli_query($conn, $products_query); $products_row = mysqli_fetch_array($products_result); $ids_array = []; do { array_push($ids_array, $products_row['id']); } while($products_row = mysqli_fetch_array($products_result)); /* echo '<pre>'; print_r($ids_array); echo '</pre>'; */ $row_counter = count($ids_array); for ($i=0; $i < $row_counter; $i++) { $current_row = $ids_array[$i]; $rand = rand(1000000 , 9999999); mysqli_query($conn , "UPDATE products SET code='$rand' WHERE id='$current_row'"); }
źródło