做一会儿/循环以获得10个随机结果

时间:2012-03-30 15:12:02

标签: php mysql sql

您好我正在尝试为我的网站制作一个标记脚本,因此每次搜索引擎访问我的网站时,我的网站上都会显示10个不同的标记。

这些标签将从数据库中获取。 所以,在我编写它的那一刻,它只抓取一个。 (因为我不知道如何做while

喜欢这样

$sql = "SELECT tagname FROM tags ORDER BY rand() LIMIT 10";
$result = mysql_query($sql);
$row = mysql_fetch_object($result);
echo "<a href='index.php'>" .$row->tagname. " </a>";

无论如何我可以添加一段时间,所以它会做10次吗?例如,使用相同的回声,但打印出10个结果而不是1 ....我已经将限制从1更改为10但是这不起作用...仍然显示一个......

3 个答案:

答案 0 :(得分:27)

停止使用ORDER BY RAND() 。停下来。此操作具有n*log2(n)的复杂性,这意味着在查询上花费的时间将增长“

    entries  |  time units
  -------------------------
         10  |         1     /* if this takes 0.001s */
      1'000  |       300
  1'000'000  |   600'000     /* then this will need 10 minutes */

如果要生成随机结果,请创建一个生成它们的存储过程。这样的事情(代码来自this article,您应该阅读):

DELIMITER $$
DROP PROCEDURE IF EXISTS get_rands$$
CREATE PROCEDURE get_rands(IN cnt INT)
BEGIN
  DROP TEMPORARY TABLE IF EXISTS rands;
  CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) );

loop_me: LOOP
    IF cnt < 1 THEN
      LEAVE loop_me;
    END IF;

    SET cnt = cnt - 1;

    INSERT INTO rands
       SELECT tags.tagname
         FROM tags 
         JOIN (SELECT (RAND()*(SELECT MAX(tags.id) FROM tags)) AS id) AS choices
        WHERE tags.id >= choices.id
        LIMIT 1;

  END LOOP loop_me;
END$$
DELIMITER ;

要使用它,你会写:

CALL get_rands(10);
SELECT * FROM rands;

至于在PHP端执行所有操作,您应该停止使用古老的mysql_* API。它已超过10年,不再维护。社区甚至begun process弃用它们。 2012年不应再使用mysql_*编写新代码了。相反,您应该使用PDOMySQLi。至于如何编写它(使用PDO):

// creates DB connection
$connection = new PDO('mysql:host=localhost;dbname=mydb;charset=UTF-8', 
                      'username', 'password');
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

// executes the procedure and creates select statement
$connection->exec('CALL get_rands(10)');
$statement = $connection->query('SELECT * FROM rands');

// performs query and collects all the info
if ($statement->execute())
{
    $tags = $statement->fetchAll(PDO::FETCH::ASSOC);
}

更新

如果要求不仅要获得10个随机结果,而且实际上 10个UNIQUE随机结果,则需要对PROCEDURE进行两次更改:

  1. 临时表应强制执行条目的唯一性:

    CREATE TEMPORARY TABLE rands ( tagname VARCHAR(63) UNIQUE);
    

    收集ID而不是值也可能有意义。特别是如果你要找的是10篇独特的文章,而不仅仅是标签。

  2. 找到重复值时,cnt计数器不应减少。这可以通过添加HANDLER(在LOOP的定义之前)来确保,这将“捕获”引发的警告,并调整计数器:

    DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;
    

答案 1 :(得分:-1)

请注意,在真实答案之前阅读:对于那些一直在低估这个答案的人。阅读标题(以“做一段时间”开头)和最后一部分,问题(“无论如何我可以添加一段时间,所以它做到了10倍 ?”)。这个答案是关于迭代结果集,而不是关于RAND函数的使用!查询甚至没有出现在我的答案中,我也建议在最后采用不同的方法:


你只需要在循环中包含对mysql_fetch_object的调用

$result = mysql_query($sql);

while ($row = mysql_fetch_object($result))
{
echo "<a href='index.php'>" .$row->tagname. " </a>";
}

稍后修改 其他考虑因素是:

  • 如果表中包含大量数据(但似乎不会),则按rand()排序会对性能产生不良影响
  • 考虑使用pdo(或至少是mysqli)
  • 即使查询似乎也应该有一些错误处理 完美,至少

    if(!$ result) { echo mysql_error(); 死; }

答案 2 :(得分:-3)

您只提取其中一个

您需要暂时逐一获取所有这些

$sql = "SELECT tagname FROM tags ORDER BY rand() LIMIT 10";
$result = mysql_query($sql);
while($row = mysql_fetch_object($result)) {
    echo "<a href='index.php'>" .$row->tagname. " </a>";
}