UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL
Answers:
代替rand()
,使用newid()
,对结果中的每一行都重新计算。通常的方法是使用校验和的模。请注意,这checksum(newid())
可能产生-2,147,483,648并导致上的整数溢出abs()
,因此我们需要在对校验和返回值进行模运算之前将其转换为绝对值。
UPDATE CattleProds
SET SheepTherapy = abs(checksum(NewId()) % 10000)
WHERE SheepTherapy IS NULL
这将生成一个介于0和9999之间的随机数。
如果您使用的是SQL Server 2008,也可以使用
CRYPT_GEN_RANDOM(2) % 10000
这似乎更简单(它也按行计算一次,newid
如下所示)
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
返回值(2个随机的可能不同的数字)
col1
----------------------
9693
8573
考虑无法解释的下降投票,我能想到的唯一合理原因是,因为生成的随机数在0-65535之间,不能被10,000整除,所以有些数字会略有超出。一种解决方法是将其包装在标量UDF中,该标量UDF会丢弃超过60,000的任何数字,然后递归调用自身以获取替换数字。
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
虽然我确实喜欢使用CHECKSUM,但我觉得使用它是一种更好的方法NEWID()
,因为您不必经过复杂的数学运算即可生成简单的数字。
ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
您可以将1000
您要设置为限制的数字替换为,并且始终可以使用加号来创建范围,例如,您想要在100
和之间的随机数200
,可以执行以下操作:
100 + ROUND( 100 *RAND(convert(varbinary, newid())), 0)
将其放到您的查询中:
UPDATE CattleProds
SET SheepTherapy= ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
WHERE SheepTherapy IS NULL
我针对RAND()测试了2种基于集合的随机方法,每个方法都产生了100,000,000行。为了平整该字段,输出是一个介于0-1之间的浮点,以模拟RAND()。大多数代码正在测试基础结构,因此我在这里总结算法:
-- 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
显然,使用CRYPT_GEN_RANDOM是最随机的,因为从一组10 ^ 18的数字中抽出10 ^ 8的数字时,甚至只有.000000001%的机会看到甚至1个重复项。哎呀,我们不应该看到任何重复的,而且没有!在我的笔记本电脑上生成此设置花了44秒钟。
Cnt Pct
----- ----
1 100.000000 --No duplicates
SQL Server执行时间:CPU时间= 134795毫秒,经过的时间= 39274毫秒。
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;
这种方法的随机性降低了近15个数量级,其速度并不快两倍,仅需23秒即可生成1亿个数字。
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执行时间:CPU时间= 77156 ms,经过的时间= 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()本身对于基于集合的生成毫无用处,因此生成用于比较随机性的基准要花费6个小时以上的时间,必须重新启动几次才能最终获得正确数量的输出行。看起来随机性还有很多需要改进的地方,尽管它比使用checksum(newid())重新设定每行的种子更好。
Cnt Pct
---- ----
1 99.768020
2 00.115840
3 00.000100 -- at least there were comparitively few values returned 3 times
由于重新启动,无法捕获执行时间。
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'");
}