Подтвердить что ты не робот

Как заполнить столбец случайными числами в SQL? Я получаю то же значение в каждой строке

UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL

Если я затем сделаю SELECT, я вижу, что мое случайное число идентично в каждой строке. Любые идеи о том, как создавать уникальные случайные числа?

4b9b3361

Ответ 1

Вместо rand() используйте newid(), который пересчитывается для каждой строки результата. Обычный способ - использовать по модулю контрольной суммы. Обратите внимание, что checksum(newid()) может генерировать -2,147,483,648 и вызывать целочисленное переполнение на abs(), поэтому нам нужно использовать modulo для возвращаемого значения контрольной суммы, прежде чем преобразовать его в абсолютное значение.

UPDATE CattleProds
SET    SheepTherapy = abs(checksum(NewId()) % 10000)
WHERE  SheepTherapy IS NULL

Это генерирует случайное число между 0 и 9999.

Ответ 2

Если вы используете 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, который выбрасывает любое число более 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  

Ответ 3

В то время как я действительно люблю использовать 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

Ответ 4

Я тестировал 2 метода рандомизации на основе набора для RAND(), генерируя по 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 было, безусловно, наиболее случайным, так как существует только вероятность .000000001% видеть даже 1 дубликат, когда выщипывает 10 ^ 8 чисел из набора из 10 ^ 18 чисел. IOW мы не должны были видеть дубликатов, и этого не было! Этот набор занял 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 секунды, чтобы генерировать 100 М чисел.

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 мс, прошедшее время = 24613 мс.

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 часов и ее необходимо перезапустить несколько раз, чтобы, наконец, получить правильное количество выходных строк. Также кажется, что случайность оставляет желать лучшего, хотя это лучше, чем использование контрольной суммы (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;

Ответ 5

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'");
}