【问题标题】:Doing a while / loop to get 10 random results做一个while /循环以获得10个随机结果
【发布时间】:2012-04-14 07:10:32
【问题描述】:

您好,我正在尝试为我的网站制作标签脚本,因此每次搜索引擎访问我的网站时,我的网站上都会显示 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,但这不起作用...仍然显示一个...

【问题讨论】:

标签: php mysql sql


【解决方案1】:

注意,在真正的答案之前阅读:对于那些一直反对这个答案的人。阅读标题(以“Doing a while”开头)和最后一部分,即问题(“无论如何我可以add a while,所以它做到了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)
  • 即使查询似乎是,您也应该进行一些错误处理 至少是完美的

    如果 (!$result) { 回声 mysql_error(); 死; }

【讨论】:

  • 感谢这个工作不好的标记,当它允许我时它有正确的答案。再次感谢
  • -1 : 使用ORDER BY RAND() 是不好的做法,结果集很大。
  • @tereško 答案是关于如何迭代结果(mysql_fetch_object 函数的使用);该查询的使用已经由 OP 完成,如果您在投票之前真的阅读了我的回答,您会看到我推荐 1) choosing another algorithm to get random results 2) pdo 3) 错误处理..
【解决方案2】:

你只获取其中一个

你需要不时地把它们一个一个地取出来

$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>";
}

【讨论】:

  • -1 : 使用ORDER BY RAND() 是不好的做法,结果集很大,另外,请不要向人们建议使用古老的mysql_* 函数。
【解决方案3】:

停止使用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 个唯一的随机结果,则需要对 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;
    

【讨论】:

猜你喜欢
  • 2020-04-28
  • 2019-03-08
  • 2018-06-25
  • 2012-09-28
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
相关资源
最近更新 更多