从mysql表

时间:2016-07-06 03:52:23

标签: mysql random selection weighted

我试图编写一个查询,从表中随机选择一些文章,但文章有加权机会被选中。我提出了一个解决方案,但对我来说似乎很笨拙,我想知道是否有人对如何做得更好有任何想法。我至少需要一篇文章,但如果查询一次返回几个文章会很有帮助。

这是我的方法:

表 -

mysql> describe randomiser;
+---------+----------------------+------+-----+---------+----------------+
| Field   | Type                 | Null | Key | Default | Extra          |
+---------+----------------------+------+-----+---------+----------------+
| id      | int(10) unsigned     | NO   | PRI | NULL    | auto_increment |
| article | varchar(30)          | YES  |     | NULL    |                |
| chance  | smallint(5) unsigned | NO   | MUL | 1       |                |
| low     | int(10) unsigned     | NO   | MUL | 0       |                |
| high    | int(10) unsigned     | NO   |     | 0       |                |
+---------+----------------------+------+-----+---------+----------------+

我的测试人群 -

mysql> select * from randomiser;
+----+-------------+--------+-----+------+
| id | article     | chance | low | high |
+----+-------------+--------+-----+------+
|  1 | common      |    128 |   1 |  128 |
|  2 | uncommon    |     64 | 129 |  192 |
|  3 | infrequent1 |     32 | 193 |  224 |
|  4 | infrequent2 |     32 | 225 |  256 |
|  5 | infrequent3 |     32 | 257 |  288 |
+----+-------------+--------+-----+------+

只要有人在表格中添加新文章,就会在插入时更新低值和高值。

我的选择方法 -

SET @t:=(SELECT FLOOR( SUM(chance) * RAND() + 1) FROM randomiser);
SELECT article FROM randomiser WHERE @t >= low AND @t <= high;
  1. 是否可以将选择组合成一个有效的语句?
  2. 是否可以编写一个选择来拉取几个随机值而不是只有一个?
  3. 注意 - 我根本没有定义它,因为我已经定义了它;如果有不同的布局,那么它会更有效率,我想知道!

2 个答案:

答案 0 :(得分:1)

您可以使用以下查询

select t.article from
(SELECT article,
case when FLOOR( SUM(chance) * RAND() + 1) between low and high
         then 1 else 0 end as chance
FROM randomiser 
group by article) t
where t.chance = 1

以上将使用多个随机值

答案 1 :(得分:1)

对于一个查询,您可以这样做:

SELECT article
FROM randomiser
WHERE (SELECT FLOOR( SUM(chance) * RAND() + 1) FROM randomiser) BETWEEN low AND high;

SQLFiddle Demo

或使用INNER JOIN

SELECT article, `range`
FROM randomiser
INNER JOIN (
    SELECT
        FLOOR( SUM(chance) * RAND() + 1) AS `range`
    FROM randomiser
) t
WHERE `range` >= low AND `range` <= high;

SQLFiddle Demo