php - 通过 MySQL 获取最少随机记录集

标签 php mysql sql random

我正在尝试找到一种获取 X 条随机记录的正确方法。另外,我想检查特定记录的使用情况,这样我就不会像其他人一样频繁地使用相同的随机记录。

我正在使用这 3 个表来测试该集,其中一个用于问题的表,一个用于用户的表,一个用于特定用户的所提供问题的表。我想用大约 6000 个问题来完成这个任务。

CREATE TABLE `questions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `question` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `served` (
  `user` int(11) NOT NULL DEFAULT '0',
  `question` int(11) NOT NULL DEFAULT '0',
  `count` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`user`,`question`),
  KEY `count` (`count`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nickname` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我发现从问题表中获取随机记录的查询非常有效,如下所示:

SELECT  id, question
        FROM    (
                SELECT  @cnt := COUNT(*) + 1,
                        @lim := 10
                FROM    questions
                ) vars
        STRAIGHT_JOIN
                (
                SELECT  q.*,
                        @lim := @lim - 1
                FROM    questions q 
                WHERE   (@cnt := @cnt - 1)
                        AND RAND() < @lim / @cnt
                ) i

但现在我想合并已提供的表,以确保从提供最少的问题中挑选随机值。我想到的查询如下:

SELECT  id, question, count
        FROM    (
                SELECT  @cnt := COUNT(*) + 1,
                        @lim := 10
                FROM    questions
                ) vars
        STRAIGHT_JOIN
                (
                SELECT  q.*,
                        s.count,
                        @lim := @lim - 1
                FROM    questions q
                LEFT JOIN served s
                ON s.question = q.id
                WHERE   (@cnt := @cnt - 1)
                        AND RAND() < @lim / @cnt
                ORDER BY count ASC) i

这个查询的问题是它永远不会给出 10 个结果的限制 + 它永远不会给出我想要的记录。有人能把我推向正确的方向吗?

根据要求,使用一些数据进行 SQL Fiddle 测试:http://sqlfiddle.com/#!2/3e5ed/5 。我希望结果是 10 个问题,其中为用户 1 提供的服务“计数”最少(或不存在)。

我最终使用了修改后的查询,它必须很快:

SELECT q.*, s1.count AS count_a, s2.count AS count_b
FROM questions q
LEFT JOIN served s1
ON (s1.question = q.id AND s1.user = 1)
LEFT JOIN served s2
ON (s2.question = q.id AND s2.user = 2)
WHERE q.categorie = 1
ORDER BY IFNULL(s1.count, 0) + IFNULL(s2.count, 0) + RAND()
LIMIT 10

最佳答案

人们在 MySQL 中获取随机记录的常见方式是这样的:

获取 10 条随机记录:

SELECT * FROM questions
ORDER BY RAND()
LIMIT 10

当然,显而易见的是,这会获取数据库中的所有记录,然后对它们进行随机排序以获得 10 条记录。它实际上不只是从数据库中随机选择 10 条记录。然而,这种方法确实很容易防止重复。

现在,使用相同的技术,如果您想支持较少提供的问题,您可以执行以下操作:

SELECT questions.* FROM questions
LEFT JOIN served
ON served.question = questions.id
ORDER BY IFNULL(served.count, 0) + RAND()
LIMIT 10

调整算法以改变您喜欢的发球次数。

有更高效的方法来获取随机记录,例如获取最大主键值(假设 auto_increment),然后使用 RAND() ,然后仅选择一条记录。您可以使用 LIMIT 1 以防 RAND() 返回键中的间隙。但是,如果重复此过程以返回多个记录,则可能会出现重复项。

如果您有连续的 auto_increment 值,您可以轻松地利用 PHP 来选择一组随机键,然后单独获取每个记录。如果它们不连续,您首先获取键列表。

这些技术在本书 SQL Antipatterns 第 16 章随机选择中有更详细的介绍。 .

关于php - 通过 MySQL 获取最少随机记录集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21186759/

相关文章:

PHP MySQL 选择日期时间值在过去 n 分钟内的行

mysql - sql查询 - 结果错误

sql - MERGE 语句问题 - 分号错误 (SQL Server 2008)

sql - 免费的 SQL 比较工具

mysql - 在 SQL 中添加行之前检查表中是否存在行

php - 正则表达式从正则表达式代码中排除 1 个单词

php - 写入 joomla Assets 表的正确模式是什么?

php - Zend 3 + Doctrine 2 创建表格?

php - 如何在同一资源LARAVEL中返回数据透视表的数据

mysql - 错误 1060 (42S21) : Duplicate column name 'eid'