【问题标题】:Getting Next and Previous from MySQL When Dates Are the Same当日期相同时从 MySQL 获取下一个和上一个
【发布时间】:2015-11-04 12:43:27
【问题描述】:

现在我遇到了一个问题,因为从外部源将行导入我的数据库发生得太快了。

如果创建了多行具有完全相同的发布日期,则无法按日期排序并顺序滚动浏览帖子。

假设五行都是在上午 11:22:04 准确生成的:

  • 第 1 行 - 上午 11:22:04
  • 第 2 行 - 上午 11:22:04
  • 第 3 行 - 上午 11:22:04
  • 第 4 行 - 上午 11:22:04
  • 第 5 行 - 上午 11:22:04

如果访问者正在查看第 3 行并想要“下一行”,我将要求数据库提供晚于或等于上午 11:22:04 发布的下一行,即第 1 行不管我做什么。

  • 如果我不说“或等于”,那只会意味着访问者永远不会看到第 4 行或第 5 行,这与总是看到第 1 行一样糟糕。
  • 将行 ID 添加到 order by 子句无济于事,因为 -- 再说一遍 -- 它只会给我第 1 行(如果我目前正在查看第 3 行)。
  • 在where 子句中添加大于或小于没有帮助,因为——例如——如果我正在查看第 3 行并且我想要“下一个”行但说 ID 需要是大于 3,那么我永远不会得到第 1 行。

我可以通过更新同时发布的数据库中的每一行以该行的ID为秒来欺骗系统,这会将上述记录变成:

  • 第 1 行 - 上午 11:22:01
  • 第 2 行 - 上午 11:22:02
  • 第 3 行 - 上午 11:22:03
  • 第 4 行 - 上午 11:22:04
  • 第 5 行 - 上午 11:22:05

实际上效果很好。问题是每次管理员导入数据时都会添加新行,而我无法不断更新数据库来纠正这个问题。

我获取下一个和上一个的查询如下所示:

// next row
select  t.*
from    table t
where   t.postdate  >= '{$current_date}'
and     t.postdate  < now()
and     t.id        <> {$current_id}
order   by t.postdate
limit   1

// previous row
select  t.*
from    table t
where   t.postdate  <= '{$current_date}'
and     t.postdate  < now()
and     t.id        <> {$current_id}
order   by t.postdate desc
limit   1

(是的,我在 Google 上对此进行了广泛的搜索,并在 Stackoverflow 上查看了几个类似的问题!)

【问题讨论】:

  • 你看过用 sql 跳过行的命令吗?我认为 OFFSET 是常见的命令,尽管从未使用过。不过这些也可能相关:stackoverflow.com/questions/16568/…stackoverflow.com/questions/758186/…。也许添加第二个 ORDER 字段并可以使用它
  • 你有auto_inc int吗,如果没有你能加一个吗,如果我在上面错过了,对不起
  • @DanielBrose 我看不出跳过行和/或使用 OFFSET 如何以任何方式帮助解决问题。我尝试了多个不同的 ORDER BY 子句,但一直遇到同样的问题。
  • @Drew 是的,每一行都有一个 auto_increment 字段。使用它并没有帮助,因为它只是意味着我总是会得到 - 例如 - 第 1 行作为“下一个”行,无论我目前是在第 3 行还是第 4 行。
  • @DavidVincentGagne - 我假设您的 ID 是自动增量的。因此,如果您的 ORDER BY 有 2 个字段,即 postdate THEN id,那么使用“and t.id > {$current_id}”应该对其进行排序。偏移量可能没有那么有用,因为假设知道总行数等,但你总是可以假设如果 postdate 相同,ID 会更大

标签: php mysql


【解决方案1】:

你可以试试这样的:

// next row
select  t.*
from    table t
where   CONCAT(t.postdate, t.id)  >= '{$current_date}{$current_id}'
and     t.postdate  < now()
and     t.id        <> {$current_id}
order   by t.postdate
limit   1

// previous row
select  t.*
from    table t
where   CONCAT(t.postdate, t.id)  <= '{$current_date}{$current_id}'
and     t.postdate  < now()
and     t.id        <> {$current_id}
order   by t.postdate desc
limit   1

【讨论】:

  • 我正在尝试这个,它适用于几个测试用例。我对连接DATETIME 和INT(11) 持谨慎态度,但这似乎没问题。直到或除非我遇到问题——我将在接下来的几周内进行相当多的测试! ——我将把它作为最好的答案。谢谢!
【解决方案2】:

假设

主要假设ID字段是auto_increment。

利用它

// next row
select  t.*
from    table t
where   (( t.postdate  = '{$current_date}' AND  t.id > {$current_id})
OR t.postdate  > '{$current_date}')
and     t.postdate  < now()
order   by t.postdate, t.id
limit   1

// previous row
select  t.*
from    table t
where   (( t.postdate  = '{$current_date}' AND  t.id < {$current_id})
OR t.postdate  < '{$current_date}')
and     t.postdate  < now()
order   by t.postdate desc, t.id DESC
limit   1

就这么简单。

也许稍微使用确切的语法来获得你想要的结果(按 asc 或 desc、> 或

sql有点生疏,所以也要确认语法,但是显式的id检查将始终确保如果相同的postdate通过id进一步区分。

更新

将 ACS 或 DESC 添加到 ORDER BY t.id 以帮助确保所有行都是可选的,如 cmets 中所述

更新

sqlfiddle 证明了这个概念:http://sqlfiddle.com/#!9/70e01/18

我的第一个 sqlfiddle,如有错误请原谅,但对我来说很好。

【讨论】:

  • 不,抱歉。你会遇到我在原来的问题中以这种方式解释的同样的问题。假设您登陆第 3 行。如果您说您想要“下一个”帖子(日期相同但 ID 更大),那么是的,您将获得第 4 行。但是如果您想要“上一个”帖子(其中日期相同但 ID 较低)那么您只会获得第 1 行,而永远不会获得第 2 行(因为您必须先按日期排序,然后按 ID 排序,因为不是 all日期相同)。
  • @DavidVincentGagne - 我确实仔细阅读了您的 cmets,我确实必须编辑错字对不起,但范围应该允许适当的或类型检查。您的 ID 可以更大或更小,或者日期不同。以这种方式,第 1 行保持可选状态。
  • 对不起,我在解释完之前点击了上一条评论的[return]。它现在已更新(希望)解释为什么使用 auto_increment 字段没有帮助。
  • @DavidVincentGagne - 谢谢,我有发布然后自己编辑和编辑的坏习惯;)我无法测试语法,但请查看我的编辑以及将 ACS 或 DESC 添加到 t.id 排序会解决这个问题
  • 对不起。我感谢你的努力,但你仍然会得到相同的结果。您的“下一个”示例每次只会返回第 1 行。
猜你喜欢
  • 2022-01-16
  • 1970-01-01
  • 2012-12-11
  • 2016-03-24
  • 2016-04-05
  • 1970-01-01
  • 2021-03-30
  • 2017-02-27
  • 1970-01-01
相关资源
最近更新 更多