在MySQL中查找下一行/上一行

时间:2014-10-09 23:18:39

标签: mysql

我的PHP页面查询文件表,用户可以单击页面上的列,按标题,日期,大小,状态和上传用户名称进行排序。然后,他们可以单击每个文件,在单独的播放器页面中查看它。

我想要做的是在播放器中创建上一个/下一个按钮,以转到文件页面上订购的上一个或下一个文件。这意味着可以通过上面列出的任何参数对结果进行排序。

对于像日期这样的东西,它很简单:

SELECT * FROM Files WHERE date > curdate ORDER BY date LIMIT 1

但是,其他一些参数导致了我的问题:

  • 如何处理字符串,例如上传用户的姓名?

  • 如何处理已排序列中的下一项具有相同值的情况?例如,status是介于0和3之间的int,大多数文件的状态为0.如果我按“状态”页面上的状态排序,则会先列出状态为0的所有文件,然后是状态1,等等。当前文件位于0状态文件的中间,如何找出下一个状态为0的状态?

(P.S。我知道这个主题有很多主题,但我没有看到解决上述具体情况的问题。)

1 个答案:

答案 0 :(得分:3)

问:我如何处理类似上传用户名称的字符串?

A:与处理日期和数字的方式相同。字符串也是“可订购的”。

问:如何处理排序列中下一项具有相同值的情况?

答:与处理非唯一日期的重复值的方式相同。除了“主要”排序列之外,您还需要另一个独特的“次要”排序列,或者“主要”和“次要”组合在一起是唯一的。

理想情况下,您可以在非可空列上使用PRIMARY KEY或UNIQUE KEY作为“次要”排序顺序。

“技巧”是保存列表中的当前位置,方法是将“最后看到的”行保存为主要值和次要值,然后在查询中使用该信息以获取“下一页”。

    WHERE t.major >= :last_seen_major
      AND (t.major > :last_seen_major OR t.minor > :last_seen_minor)
    ORDER BY t.major ASC, t.minor ASC
    LIMIT 1

从最后一行(在这种情况下,只有一行),您需要保存主列和次列的值,以便可以在同一查询中使用这些值以获取“下一行”。

为了获得最佳查询效果,您需要一个可用前导列为(major, minor)的索引。

根据您的查询,假设您有id列,您可以执行以下操作:

SELECT f.*
  FROM Files f 
 WHERE f.date >= :last_seen_date
   AND (f.date > :last_seen_date OR f.id > :last_seen_id)
 ORDER BY f.date ASC, f.id ASC
 LIMIT 1

要按其他列排序,请将WHERE和ORDER BY子句中的f.date替换为其他内容,例如: f.name


性能较差的替代

另一种非常流行的方法是在LIMIT子句中使用“offset”。

乍一看,这似乎是一个优雅的解决方案,但它确实有一些麻烦。

你可以这样做:

ORDER BY major ASC, minor ASC LIMIT 41,1 

对于“下一行”,您将偏移量增加1

ORDER BY major ASC, minor ASC LIMIT 42,1 

此方法存在一个问题,如果在已经看到的行范围内插入行,则“下一个”查询将返回相同的行。因为第41行现在是第42行。如果有人删除了一行,“下一个”查询将跳过一行。而且我不愿意在我的“获得下一行”功能中遇到这种缺陷。这种方法仍然需要跟踪列表中的位置,但是通过携带额外的偏移量而不是行的一部分。

这种方法的另一个问题是数据库必须检索行,然后对它们进行排序,然后最后应用LIMIT子句,这可能是大型集的性能问题。