UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Se poi eseguo una SELEZIONE vedo che il mio numero casuale è identico in ogni riga . Qualche idea su come generare numeri casuali univoci?
UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Se poi eseguo una SELEZIONE vedo che il mio numero casuale è identico in ogni riga . Qualche idea su come generare numeri casuali univoci?
Risposte:
Invece di rand(), usa newid(), che viene ricalcolato per ogni riga nel risultato. Il modo usuale è usare il modulo del checksum. Si noti che checksum(newid())può produrre -2,147,483,648 e causare un overflow di numeri interi abs(), quindi è necessario utilizzare modulo sul valore di ritorno del checksum prima di convertirlo in valore assoluto.
UPDATE CattleProds
SET SheepTherapy = abs(checksum(NewId()) % 10000)
WHERE SheepTherapy IS NULL
Questo genera un numero casuale compreso tra 0 e 9999.
Se sei su SQL Server 2008 puoi anche usare
CRYPT_GEN_RANDOM(2) % 10000
Che sembra un po 'più semplice (viene valutato anche una volta per riga così com'è newid- mostrato di seguito)
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
Restituisce (2 numeri casuali probabilmente diversi )
col1
----------------------
9693
8573
Riflettendo sull'inspiegabile downvote, l'unica ragione legittima a cui posso pensare è che, poiché il numero casuale generato è compreso tra 0-65535, che non è uniformemente divisibile per 10.000, alcuni numeri saranno leggermente sovrarappresentati. Un modo per aggirare questo sarebbe avvolgerlo in una UDF scalare che butta via qualsiasi numero superiore a 60.000 e chiama se stesso in modo ricorsivo per ottenere un numero sostitutivo.
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
Anche se adoro usare CHECKSUM, ritengo che un modo migliore di procedere sia quello di utilizzarlo NEWID(), solo perché non è necessario eseguire calcoli complicati per generare numeri semplici.
ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
Puoi sostituire il 1000con qualsiasi numero che desideri impostare come limite e puoi sempre utilizzare un segno più per creare un intervallo, diciamo che desideri un numero casuale compreso tra 100e 200, puoi fare qualcosa come:
100 + ROUND( 100 *RAND(convert(varbinary, newid())), 0)
Mettendolo insieme nella tua query:
UPDATE CattleProds
SET SheepTherapy= ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
WHERE SheepTherapy IS NULL
Ho testato 2 metodi di randomizzazione basati su set contro RAND () generando 100.000.000 di righe con ciascuno. Per livellare il campo, l'output è un float tra 0-1 per imitare RAND (). La maggior parte del codice sta testando l'infrastruttura, quindi riassumo gli algoritmi qui:
-- 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
L'uso di CRYPT_GEN_RANDOM è stato chiaramente il più casuale poiché c'è solo una probabilità dello 0,000000001% di vedere anche 1 duplicato quando si strappano 10 ^ 8 numeri da un insieme di 10 ^ 18 numeri. IOW non avremmo dovuto vedere alcun duplicato e questo non ne aveva! Questo set ha impiegato 44 secondi per essere generato sul mio laptop.
Cnt Pct
----- ----
1 100.000000 --No duplicates
Tempi di esecuzione di SQL Server: tempo CPU = 134795 ms, tempo trascorso = 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 quasi 15 ordini di grandezza meno casuali, questo metodo non era due volte più veloce, impiegando solo 23 secondi per generare 100 milioni di numeri.
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
Tempi di esecuzione di SQL Server: tempo CPU = 77156 ms, tempo trascorso = 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 () da solo è inutile per la generazione basata su set, quindi la generazione della linea di base per il confronto della casualità ha richiesto più di 6 ore e ha dovuto essere riavviata più volte per ottenere finalmente il giusto numero di righe di output. Sembra anche che la casualità lasci molto a desiderare, sebbene sia meglio che usare checksum (newid ()) per riseminare ogni riga.
Cnt Pct
---- ----
1 99.768020
2 00.115840
3 00.000100 -- at least there were comparitively few values returned 3 times
A causa dei riavvii, non è stato possibile acquisire il tempo di esecuzione.
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;
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'");
}