【问题标题】:Order of an item in MySQL query resultMySQL查询结果中项目的顺序
【发布时间】:2010-11-25 18:46:12
【问题描述】:

有没有办法通过遍历整个集合来知道查询结果中特定项目的顺序?

我有一个以 Ajaxified 方式显示用户 cmets 的 Web 应用程序,我想向用户发送一个指向他们的 cmets 的链接,如下所示:

http://my.web/post/12345#comment_45

并使用哈希值“comment_45”加载带有给定评论的评论页面,但我不知道如何通过遍历整个结果来获取正确的页面。

谢谢

【问题讨论】:

    标签: php sql mysql ajax


    【解决方案1】:

    我不知道这个 URL 是如何或在哪里生成的,但我假设如果你知道创建 URL 时是哪条评论,你应该在以后知道。听起来每条评论都有一个唯一的 ID(如果没有,它应该)。

    我不认为让comment_45引用某个页面上的某个评论是稍后检索评论的可靠方式(如果页面中或另一个页面上的另一个评论被删除怎么办?如果您更改多少个cmets怎么办?显示在页面上?等)

    如果 cmets 有一个 ID,并且您的 URL 中的“comment_45”实际上就是这个 ID,您可以使用以下通用 SQL 查询来只检索这个评论:

    select field1, field2, ... fieldn from comments where comment_id = id;
    

    在这种情况下,id 将是一个变量,其评论 ID 由 URL 提供(comment_45 的“45”部分)。由于此信息来自不受信任的来源(互联网),因此您需要确保对输入进行清理以防止 SQL 注入。

    【讨论】:

    • 该 URL 将在用户自己的页面中找到,类似于带有指向他/她的所有 cmets 的链接的个人资料页面,我可以获得评论 ID,但我不知道评论顺序.知道顺序可以让我查看正确的页面。
    • 所以你想让其他的cmet也出现,只是页面聚焦到了链接提供的评论,有多个评论页面的可能
    【解决方案2】:

    您的 cmets 是否以合理的方式订购?如果它们总是以从第一个到最后一个(或从最后一个到第一个)的数字顺序显示,您应该能够根据知道 a) cmets 的总数,b) 每页的 cmets 数来计算它所在的页面。

    【讨论】:

    • cmets 按时间排序(较新的在前),因此 ID 为 45 的用户的评论可能在上午出现在第 1 页,下午出现在第 4 页。
    • 是的,但是如果您知道总共有多少 cmets,那么您只需向后工作 - 例如,如果您总共有 120 cmets,每页有 25 cmets,那么您知道 120 到96 将在第 1 页上,95 到 71 将在第 2 页上,70 到 46 将在第 3 页上,因此 45 将是第 4 页上的第一个评论。您需要确定的唯一信息是 3 个数字总 cmets、每页 cmets 和目标评论数。假设您的页面从 1 开始编号,您可以通过公式 ceil( (total-target+1) / perpage ) 找到您想要的页面。
    • 谢谢 Dav 的澄清,我有 3 个数字中的 2 个,我有总 cmets 和每页 cmets,但我没有目标评论的数量,我只有它的 ID .我可以遍历结果直到找到 ID,但这并不实用。
    • @rayed: 你不能只计算在你感兴趣的评论之前出现的 cmets 的数量吗(我假设评论 ID 是使用自动增量字段完成的并被分配按添加 cmets 的顺序)?类似于SELECT COUNT(*) FROM comments WHERE post_id = 12345 AND comment_id < 45。然后你可以使用 Dav 的算法来确定页面。
    • 正是 Ken Keenan 所建议的 - 尽管在您的特定情况下,您可能想要计算目标评论 之后 出现的 cmets,而不是之前 - 所以你想使用> 而不是 <.>
    【解决方案3】:

    根据定义,SQL 数据库中的行是无序的。为了保证后续查询的顺序相同,您必须包含“order by”子句。然后,您可以使用以下查询做您想做的事情

    SELECT * FROM `your_table` ORDER BY `date_entered` LIMIT 45, 1
    

    如果在查询之间插入或删除行,结果将不会完全符合用户的预期,但如果 order-by 字段是日期时间,这通常不是问题。

    【讨论】:

      【解决方案4】:

      我通常反对在 MySQL 中使用存储过程,因为我认为它们还不够成熟,但我认为这是创建存储过程的经典案例。

      我们仍然需要有两个查询,一个用于获取评论的顺序,一个用于获取相关行,但我找不到任何更有创意的东西可以在 1 个查询中完成,因为必须知道 LIMIT 值在执行查询之前。

      如果我们不是在谈论巨大的结果集,那么简单地获取所有结果和 cmets 顺序然后使用 array_slice 仅显示相关页面 cmets 可能会更有效。

      /* get the comment order */
      SET @commentOrder = 0;
      SELECT commentOrder INTO @relevantCommentOrder FROM (
              SELECT commentID, @commentOrder := @commentOrder+ 1 as commentOrder
              FROM COMMENTS
              ORDER BY creationDate) commentsOrder
          WHERE commentID= 45;
      /* get the value we want to use in the LIMIT clause */
      SET @startFrom = CONVERT(ROUND(ROUND(@relevantCommentOrder/10)*10) ,UNSIGNED);
      /* fetch relevant results */
      PREPARE STMT FROM 'SELECT * FROM COMMENTS LIMIT ?,10';
      EXECUTE STMT USING @startFrom;
      

      下一个是 1 个查询,它将为您提供整个结果集并将评论的顺序放在 所有行 中,这样您就可以在 PHP 中检查第一行的相关CommentOrder 字段,然后对数组进行切片所以它只会显示相关的 cmets,这个只有在整个结果集不太大的情况下才有效。

      SET @commentOrder = 0;
      SELECT *, @relevantCommentOrder;
          FROM (
         SELECT commentID, @commentOrder := @commentOrder+ 1 as commentOrder, 
                 @relevantCommentOrder := case when commentID = 45 
                                              then @commentOrder 
                                              else @relevantCommentOrder end 
            FROM COMMENTS
            ORDER BY creationDate ) subQuery;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-20
        • 2012-01-02
        • 1970-01-01
        • 1970-01-01
        • 2012-05-20
        • 2012-01-02
        • 2016-11-26
        • 1970-01-01
        相关资源
        最近更新 更多