UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Wenn ich dann SELECT mache, sehe ich, dass meine Zufallszahl in jeder Zeile identisch ist . Irgendwelche Ideen, wie man eindeutige Zufallszahlen generiert?
UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Wenn ich dann SELECT mache, sehe ich, dass meine Zufallszahl in jeder Zeile identisch ist . Irgendwelche Ideen, wie man eindeutige Zufallszahlen generiert?
Antworten:
rand()
Verwenden Sie stattdessen use newid()
, das für jede Zeile im Ergebnis neu berechnet wird. Der übliche Weg ist, das Modulo der Prüfsumme zu verwenden. Beachten Sie, dass checksum(newid())
dies -2.147.483.648 erzeugen und einen Ganzzahlüberlauf verursachen kann. Daher abs()
müssen Sie Modulo für den Prüfsummenrückgabewert verwenden, bevor Sie ihn in einen absoluten Wert konvertieren.
UPDATE CattleProds
SET SheepTherapy = abs(checksum(NewId()) % 10000)
WHERE SheepTherapy IS NULL
Dies erzeugt eine Zufallszahl zwischen 0 und 9999.
Wenn Sie mit SQL Server 2008 arbeiten, können Sie auch verwenden
CRYPT_GEN_RANDOM(2) % 10000
Was etwas einfacher erscheint (es wird auch einmal pro Zeile ausgewertet, wie newid
es unten gezeigt wird)
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
Rückgabe (2 zufällige wahrscheinlich unterschiedliche Zahlen)
col1
----------------------
9693
8573
Das einzige legitime Grund, an das ich denken kann, ist, dass einige Zahlen leicht überrepräsentiert sind, wenn die zufällige Zahl zwischen 0 und 65535 liegt, die nicht gleichmäßig durch 10.000 teilbar ist. Eine Möglichkeit, dies zu umgehen, besteht darin, es in eine skalare UDF zu verpacken, die eine beliebige Zahl über 60.000 wegwirft und sich rekursiv aufruft, um eine Ersatznummer zu erhalten.
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
Obwohl ich CHECKSUM sehr gerne benutze, denke ich, dass ein besserer Weg die Verwendung ist NEWID()
, nur weil Sie keine komplizierte Mathematik durchlaufen müssen, um einfache Zahlen zu generieren.
ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
Sie können die 1000
Zahl durch eine beliebige Zahl ersetzen, die Sie als Grenzwert festlegen möchten, und Sie können immer ein Pluszeichen verwenden, um einen Bereich zu erstellen. Nehmen wir an, Sie möchten eine Zufallszahl zwischen 100
und 200
, und Sie können Folgendes tun:
100 + ROUND( 100 *RAND(convert(varbinary, newid())), 0)
Fügen Sie es in Ihrer Anfrage zusammen:
UPDATE CattleProds
SET SheepTherapy= ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
WHERE SheepTherapy IS NULL
Ich habe 2 satzbasierte Randomisierungsmethoden gegen RAND () getestet, indem ich jeweils 100.000.000 Zeilen generiert habe. Um das Feld auszugleichen, ist der Ausgang ein Float zwischen 0-1, um RAND () nachzuahmen. Der größte Teil des Codes testet die Infrastruktur, daher fasse ich die Algorithmen hier zusammen:
-- 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
Die Verwendung von CRYPT_GEN_RANDOM war eindeutig die zufälligste, da nur eine Wahrscheinlichkeit von 0,000000001% besteht, dass beim Zupfen von 10 ^ 8 Zahlen aus einem Satz von 10 ^ 18 Zahlen sogar 1 Duplikat angezeigt wird. IOW wir hätten keine Duplikate sehen sollen und diese hatten keine! Die Erstellung dieses Sets auf meinem Laptop dauerte 44 Sekunden.
Cnt Pct
----- ----
1 100.000000 --No duplicates
SQL Server-Ausführungszeiten: CPU-Zeit = 134795 ms, verstrichene Zeit = 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;
Mit fast 15 Größenordnungen weniger zufällig war diese Methode nicht ganz doppelt so schnell und benötigte nur 23 Sekunden, um 100 Millionen Zahlen zu generieren.
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
SQL Server-Ausführungszeiten: CPU-Zeit = 77156 ms, verstrichene Zeit = 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 () allein ist für die satzbasierte Generierung nutzlos. Das Generieren der Basislinie für den Vergleich der Zufälligkeit dauerte über 6 Stunden und musste mehrmals neu gestartet werden, um schließlich die richtige Anzahl von Ausgabezeilen zu erhalten. Es scheint auch, dass die Zufälligkeit zu wünschen übrig lässt, obwohl es besser ist, als die Prüfsumme (newid ()) zu verwenden, um jede Zeile neu zu säen.
Cnt Pct
---- ----
1 99.768020
2 00.115840
3 00.000100 -- at least there were comparitively few values returned 3 times
Aufgrund der Neustarts konnte die Ausführungszeit nicht erfasst werden.
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'");
}