【发布时间】:2010-11-25 18:46:12
【问题描述】:
有没有办法通过遍历整个集合来知道查询结果中特定项目的顺序?
我有一个以 Ajaxified 方式显示用户 cmets 的 Web 应用程序,我想向用户发送一个指向他们的 cmets 的链接,如下所示:
http://my.web/post/12345#comment_45
并使用哈希值“comment_45”加载带有给定评论的评论页面,但我不知道如何通过遍历整个结果来获取正确的页面。
谢谢
【问题讨论】:
有没有办法通过遍历整个集合来知道查询结果中特定项目的顺序?
我有一个以 Ajaxified 方式显示用户 cmets 的 Web 应用程序,我想向用户发送一个指向他们的 cmets 的链接,如下所示:
http://my.web/post/12345#comment_45
并使用哈希值“comment_45”加载带有给定评论的评论页面,但我不知道如何通过遍历整个结果来获取正确的页面。
谢谢
【问题讨论】:
我不知道这个 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 注入。
【讨论】:
您的 cmets 是否以合理的方式订购?如果它们总是以从第一个到最后一个(或从最后一个到第一个)的数字顺序显示,您应该能够根据知道 a) cmets 的总数,b) 每页的 cmets 数来计算它所在的页面。
【讨论】:
ceil( (total-target+1) / perpage ) 找到您想要的页面。
SELECT COUNT(*) FROM comments WHERE post_id = 12345 AND comment_id < 45。然后你可以使用 Dav 的算法来确定页面。
根据定义,SQL 数据库中的行是无序的。为了保证后续查询的顺序相同,您必须包含“order by”子句。然后,您可以使用以下查询做您想做的事情
SELECT * FROM `your_table` ORDER BY `date_entered` LIMIT 45, 1
如果在查询之间插入或删除行,结果将不会完全符合用户的预期,但如果 order-by 字段是日期时间,这通常不是问题。
【讨论】:
我通常反对在 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;
【讨论】: