UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Si luego hago un SELECCIONAR, veo que mi número aleatorio es idéntico en cada fila . ¿Alguna idea de cómo generar números aleatorios únicos?
sql-server
NibblyPig
fuente
fuente
Si está en SQL Server 2008, también puede usar
Lo que parece algo más simple (también se evalúa una vez por fila como
newid
se muestra a continuación)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
Devuelve (2 números aleatorios probablemente diferentes )
col1 ---------------------- 9693 8573
Reflexionando sobre el voto negativo inexplicable, la única razón legítima que puedo pensar es que debido a que el número aleatorio generado está entre 0-65535, que no es divisible de manera uniforme por 10,000, algunos números estarán ligeramente sobre representados. Una forma de evitar esto sería envolverlo en una UDF escalar que deseche cualquier número superior a 60.000 y se llame a sí mismo de forma recursiva para obtener un número de reemplazo.
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
fuente
Si bien me encanta usar CHECKSUM, creo que una mejor manera de hacerlo es usar
NEWID()
, solo porque no tiene que pasar por una matemática complicada para generar números simples.Puede reemplazar el
1000
con el número que desee establecer como límite, y siempre puede usar un signo más para crear un rango, digamos que desea un número aleatorio entre100
y200
, puede hacer algo como:Poniéndolo junto en su consulta:
UPDATE CattleProds SET SheepTherapy= ROUND( 1000 *RAND(convert(varbinary, newid())), 0) WHERE SheepTherapy IS NULL
fuente
Probé 2 métodos de aleatorización basados en conjuntos contra RAND () generando 100,000,000 filas con cada uno. Para nivelar el campo, la salida es un valor flotante entre 0-1 para imitar RAND (). La mayor parte del código está probando la infraestructura, así que resumo los algoritmos aquí:
-- 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
El uso de CRYPT_GEN_RANDOM fue claramente el más aleatorio, ya que solo hay un .000000001% de probabilidad de ver incluso 1 duplicado al extraer 10 ^ 8 números DE un conjunto de 10 ^ 18 números. ¡OIA no deberíamos haber visto ningún duplicado y este no tenía ninguno! Este conjunto tardó 44 segundos en generarse en mi computadora portátil.
Cnt Pct ----- ---- 1 100.000000 --No duplicates
Tiempos de ejecución de SQL Server: tiempo de CPU = 134795 ms, tiempo transcurrido = 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;
Con casi 15 órdenes de magnitud menos aleatorios, este método no fue el doble de rápido, y solo tomó 23 segundos para generar 100 millones de números.
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
Tiempos de ejecución de SQL Server: tiempo de CPU = 77156 ms, tiempo transcurrido = 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;
RAND () solo es inútil para la generación basada en conjuntos, por lo que generar la línea de base para comparar la aleatoriedad tomó más de 6 horas y tuvo que reiniciarse varias veces para finalmente obtener el número correcto de filas de salida. También parece que la aleatoriedad deja mucho que desear, aunque es mejor que usar la suma de comprobación (newid ()) para resembrar cada fila.
Cnt Pct ---- ---- 1 99.768020 2 00.115840 3 00.000100 -- at least there were comparitively few values returned 3 times
Debido a los reinicios, no se pudo capturar el tiempo de ejecución.
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;
fuente
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'"); }
fuente