【问题标题】:Select a random row from table, but with odds?从表中选择一个随机行,但有几率?
【发布时间】:2010-03-30 21:00:35
【问题描述】:

我有一张表,描述了我系统中的各种对象(即雨伞、靴子、挎包等)。这些对象中的每一个都需要具有不同的流行率或发病率。例如,雨伞比靴子更稀有。基于这些因素,我需要根据该发生率值随机选择单个对象(包括空白或“未找到对象”)。

哎呀。有意义吗?

【问题讨论】:

  • 没有选择对象的概率应该是多少?这是存储在数据库中还是硬编码常量?

标签: php mysql codeigniter


【解决方案1】:
SELECT * FROM some_table
WHERE (100*RAND()) > some_table.percent_probability
LIMIT 1

....并且选择的概率存储在 percent_probability 字段中。

C.

【讨论】:

  • 这听起来可行,但具有误导性。例如,如果您有 5 个对象,每个对象的百分比概率为 20(认为每个对象应该出现 20% 的时间),那么 80% 的时间将返回一个项目,20% 的时间不会返回任何项目,并且其他 4 件将永远不会退还。您必须为每个项目提供 0、20、40、60 和 80 的概率,才能获得均等的机会。
  • @Syntax Error: 是的,你部分正确 - 经过反思,数学比你建议的要复杂一些,但通过随机排序并从哪里移动过滤器(在排序)到一个有子句(即之后)。
【解决方案2】:

如果您有一个写很少读的场景(即您很少更改对象和概率),您可能需要预先计算概率值,以便如果您有一个随机值,您可以明确地决定哪个要挑选的对象(只需一次挑选,无需排序,无需比较所需的所有记录)。

例如(每磨机的概率)
伞:500‰几率
靴子:250‰ 几率
书包:100‰几率
随便:100‰的机会
“无”:50‰几率

0 到 499 之间的随机数表示“雨伞”已被挑选,500-749 为“靴子”等等。

INSERT INTO foo (name, randmin, randmax) VALUES
  ('umbrella', 0, 499),  
  ('boots', 500, 749),
  ('satchel', 750, 849), 
  ('whatever', 850, 949) 

每次添加对象或修改概率时都会重新创建此表。

那么你所需要的只是一个查询

SELECT
  f.name
FROM
  (  
    SELECT Round(Rand()*1000) as r    
  )  as tmp
JOIN
  foo as f  
ON
  r BETWEEN f.randmin and f.randmax  
LIMIT
  1

只需生成一个随机值,MySQL 就可以使用 (randmin,randmax) 上的索引快速找到记录。

【讨论】:

    【解决方案3】:

    我将为此修改 symcbean 的答案,为 symcbean +1。

    SELECT * FROM some_table
    WHERE (100*RAND()) < some_table.percent_probability

    这将返回与您直观地希望分配给它们的概率相匹配的所有结果。例如,概率为 20 的 5 个对象将在 20% 的时间内全部返回。 90% 的时间将返回值为 90 的对象。

    因此,您的结果将不止一个对象,但您避免了罕见的对象经常出现。所以现在随便抓一个你的结果。一种简单的方法是将它们全部放在一个数组中,然后:

    $items = array(); // assuming you've already filled $items with your 
                      // query results, one item for each array key
    
    $count = count($items);
    
    $chosen_key = rand(1,$count)-1;
    
    $chosen_item = $items[$chosen_key];

    【讨论】:

    • 非常感谢:我正在快速尝试,看起来不错,但是当只返回一个结果时出现偏移错误? “消息:未定义的偏移量:1”
    • 我 = 哑巴。知道了。 rand() 函数从 1 开始,因此缺少 [0] 处的第一个键。
    • 已编辑以修复未定义的偏移错误。感谢您指出这一点。
    • 这个方案也有问题。第二次随机扭曲了赔率。例如,如果您有 10 条记录,赔率为 100、90、80...,并且 sql 随机数为 0.01,那么它将请求整个数据集...然后 php random 为所有记录提供相同的赔率。因此,具有“10% 机会”的记录有 10% 的机会来自 sql,然后因为有 10 条记录,它有 10% 的机会来自 PHP 随机,因此变为 1%。
    猜你喜欢
    • 2011-03-24
    • 2023-04-03
    • 2012-10-13
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多