【问题标题】:MySQL get a random value between two valuesMySQL获取两个值之间的随机值
【发布时间】:2011-09-26 20:49:58
【问题描述】:

我连续有两列:min_valuemax_value。有没有办法进行选择:

SELECT RAND(`min_v`, `max_v`) `foo` [..]

我确实意识到RAND 做了不同的事情;我想出的最接近(在帮助下)是(RAND() * (max-min))+min,虽然它会产生一个浮点数,然后我需要它到 ROUND(),这是完全错误的。

除非有人能提出替代方案(这将非常有用),否则我将采用 PHP 方式。

【问题讨论】:

  • 请描述任务。也许你根本不需要 rand()。
  • 我需要分别在min_vmax_v 列中的两个值之间获取一个随机值。

标签: php mysql


【解决方案1】:

实际上,ROUND((RAND() * (max-min))+min) 是 MySQL 中做你想做的最好的方式。它也是 ActionScript、JavaScript 和 Python 中的最佳方式。老实说,我更喜欢它而不是 PHP 方式,因为它更方便。

因为我不知道您将返回多少行,所以我无法建议您使用 PHP 还是 MySQL 更好,但如果您要处理大量值,您可能最好使用 MySQL。

附录


所以,有一个问题是 PHP 还是 MySQL 更好。我没有进入关于原则的辩论,而是执行了以下操作:

<pre><?php

$c = mysql_connect('localhost', 'root', '');

if(!$c) die('!');
echo mysql_select_db('test', $c)?'Connection':'Failure';
echo PHP_EOL;

echo ':::::::::::::::::::::::::BEGINNING MYSQL RAND::::::::::::::::::::::::::::::'.PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
    $r = mysql_query( 'SELECT ROUND(RAND() * (200-10) + 10) FROM dual' );
    $r = mysql_fetch_array( $r );
}
$end = microtime(1);

echo  ($end - $start) . " for MySQL select".PHP_EOL;

echo ':::::::::::::::::::::::::BEGINNING PHP RAND::::::::::::::::::::::::::::::' .PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
    $r = mysql_query( 'SELECT 200 AS two, 10 AS tem FROM dual' );
    $r = mysql_fetch_array( $r );
    $r[2]= rand($r[0], $r[1]);
}
$end = microtime(1);

echo  ($end - $start) . " for PHP select".PHP_EOL;

MySQL 的速度提高了大约 2-3%。

如果你使用这个,但是(注意,更多的列由 MySQL 返回):

<pre><?php

$c = mysql_connect('localhost', 'root', '');

if(!$c) die('!');
echo mysql_select_db('test', $c)?'Connection':'Failure';
echo PHP_EOL;

echo ':::::::::::::::::::::::::BEGINNING MYSQL RAND::::::::::::::::::::::::::::::'.PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
    $r = mysql_query( 'SELECT ROUND(RAND() * (200-10) + 10) as rd, 200 as two, 10 as ten FROM dual' );
    $r = mysql_fetch_array( $r );
}
$end = microtime(1);

echo  ($end - $start) . " for MySQL select".PHP_EOL;

echo ':::::::::::::::::::::::::BEGINNING PHP RAND::::::::::::::::::::::::::::::' .PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
    $r = mysql_query( 'SELECT 200 AS two, 10 AS tem FROM dual' );
    $r = mysql_fetch_array( $r );
    $r[2]= rand($r[0], $r[1]);
}
$end = microtime(1);

echo  ($end - $start) . " for PHP select".PHP_EOL;

MySQL 落后 3-4%(结果非常不一致)(如果您不对 $r[2] 使用数组索引分配,结果大致相同)。

似乎主要区别在于返回给 PHP 的记录数量,而不是随机化系统本身。因此,如果您需要 A 列、B 列和一个随机值,请使用 PHP。如果您只需要随机值,请使用 MySQL。

【讨论】:

  • 好的。我很惊讶,因为这与我期望听到的答案相反。老实说,我认为 MySQL 会比 PHP 慢很多。有人介意评论吗?作为一般做法,我总是避免在 MySQL 查询中进行任何数学运算。
  • 尝试两种方法并衡量它;)过早的优化永远不会太早!
  • 我可能是错的。我会运行一些基准测试,然后我们就知道了。
  • 这个方法有一些问题:第一个和最后一个值的概率是其他数字的两倍。但一切都取决于特定的应用需求。
  • @cwallenpoole,您使用的是静态数字,而不是列值。我敢打赌,使用实际的列值会使 MySQL 方法慢得多。
【解决方案2】:

这种方法保证每个值的统计概率相同:

SELECT FLOOR((RAND() * (max-min+1))+min)

【讨论】:

  • 我需要这两个变量之间的随机值,而不是其中一个。
  • @Guy 对不起。我不专心 :) 更新了!
  • 这与@Kyle 提供的选项相同。重复相同的答案是没有意义的。
  • @Guy 如果有人想帮助你,这并不意味着他想重复某人的回答 :) 不确定我在写这篇文章时看到了@Kyle 的回答(因为取消删除?? )。在任何情况下 +1 到 @Kyle 考虑到数学。
  • 我的问题中甚至提到了相同的答案,尽管使用的是 ROUND 而不是 FLOOR。不过两者都不好。函数应该随机执行 CEIL 或 FLOOR 才能完美运行。
【解决方案3】:

如果最小范围是 1,你可以简单地

SELECT FLOOR((RAND() * max_range) + 1)


如果最小范围为0,则可以更简单

SELECT FLOOR((RAND() * max_range))

【讨论】:

    【解决方案4】:

    你能做这样的事吗?

    SELECT id, (FLOOR( 1 + RAND( ) *60 )) AS timer
    FROM users
    LIMIT 0 , 30
    

    this post

    【讨论】:

      【解决方案5】:

      根据表中有多少行,在查询或子查询中使用 rand() 可能会非常慢。

      您可以通过首先将随机值放入变量中然后在查询中使用它来显着提高速度。

      例如在超过 400 万行的表上...

      这需要 10 多分钟:

      SELECT
          *
      FROM
          `customers` `Customer`
      WHERE
          `id` = (
              SELECT
                  FLOOR((RAND() * (max(`CustomerRand`.`id`) - min(`CustomerRand`.`id`) + 1)) + min(`CustomerRand`.`id`)) `random_id`
              FROM
                  `customers` `CustomerRand`
          );
      

      虽然这平均需要大约 3 秒:

      SELECT
         FLOOR((RAND() * (max(`CustomerRand`.`id`) - min(`CustomerRand`.`id`) + 1)) + min(`CustomerRand`.`id`)) `random_id`
      FROM `customers` `CustomerRand` INTO @rand_id;
      
      SELECT * FROM `customers` WHERE `id` = @rand_id;
      

      您甚至可以将其放入存储过程中,如果您想要经常执行或重复使用它。然后可以从 PHP 或 Python 或任何地方调用存储过程

      【讨论】:

        【解决方案6】:

        您可以使用按 rand 排序

        SELECT virtual.num
        FROM (
                 SELECT 1 AS num UNION
                 SELECT 2 AS num UNION
                 SELECT 3 AS num
             ) virtual
        ORDER BY RAND()
        LIMIT 1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-11-07
          • 1970-01-01
          • 1970-01-01
          • 2018-10-16
          • 2019-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多