【问题标题】:Fetch two next and two previous entries in a single SQL query在单个 SQL 查询中获取两个下一个和两个上一个条目
【发布时间】:2009-01-02 12:09:51
【问题描述】:

我想显示一个图片库,并且在视图页面上,应该可以看到一堆缩略图:当前图片,包含前面的两个条目和后面的两个条目。

获取两个下一个/上一个的问题是我不能(除非我弄错了)选择像 MAX(id) WHERE idxx 这样的东西。

有什么想法吗?

注意:当然 id 不跟随,因为它们应该是多个 WHERE 实例的结果。

谢谢 马歇尔

【问题讨论】:

    标签: sql mysql database


    【解决方案1】:

    请原谅 SQL Server 风格的变量名,我不记得 MySQL 是如何进行变量命名的。

    SELECT *
      FROM photos
     WHERE photo_id = @current_photo_id
     UNION ALL
    SELECT *
      FROM photos
     WHERE photo_id > @current_photo_id
     ORDER BY photo_id ASC
     LIMIT 2
     UNION ALL
    SELECT *
      FROM photos
     WHERE photo_id < @current_photo_id
     ORDER BY photo_id DESC
     LIMIT 2;
    

    此查询假定您可能有不连续的 ID。但是,从长远来看,如果您的表中有很多照片,因为经常在从数据库中检索到整个结果集之后评估 TOP,这可能会成为问题。 YMMV。

    在高负载情况下,我可能会使用这些查询,但我也会定期预实现它们,以便每张照片都有一个 PreviousPhotoOne、PreviousPhotoTwo 等列。维护起来有点多,但是当你有大量静态数据并且需要性能时,它工作得很好。

    【讨论】:

      【解决方案2】:

      如果你的 ID 是连续的,你可以这样做

      where id >= @id-2 and id <= @id+2
      

      否则我认为你必须union 3 次查询,一个以获取具有给定 id 的记录,另外两个与 toporder by 这样搞乱

      select *
      from table
      where id = @id
      
      union
      
      select top 2 *
      from table
      where id < @id
      order by id desc
      
      union
      
      select top 2 *
      from table
      where id > @id
      order by id
      

      性能不会太差,因为您没有检索大量数据集,但由于使用union,性能不会很好。

      如果您发现性能开始出现问题,您可以添加列来保存上一个和下一个项目的 ID;使用触发器或通宵过程或其他方式计算 id。这意味着您只需执行一次硬查询,而不是每次需要时执行。

      【讨论】:

      • 注意:“TOP 2”是专有的 Microsoft/Sybase 语法,MySQL 不支持。相反,MySQL 使用出现在 ORDER BY 子句之后的可选 LIMIT 子句。
      【解决方案3】:

      我认为这种方法应该适用于非连续 ID,并且应该比使用 UNION 更有效。 currentID 将使用 SQL 中的常量或从您的程序传递来设置。

      SELECT * FROM photos WHERE ID = currentID OR ID IN (
          SELECT ID FROM photos WHERE ID < currentID ORDER BY ID DESC LIMIT 2
      ) OR ID IN (
          SELECT ID FROM photos WHERE ID > currentID ORDER BY ID ASC LIMIT 2
      ) ORDER BY ID ASC
      

      【讨论】:

      • 您不应该在 WHERE 子句中使用 OR 而不是 AND 吗?
      【解决方案4】:

      如果您只是对 id 的上一条和下一条记录感兴趣,您不能只使用一个 where 子句来限制 WHERE id=xx, xx-1, xx-1, xx+1, xx+2 使用多个 WHERE子句或使用 WHERE IN ?

      【讨论】:

      • 这将适用于您有一个连续的标识列的理想世界,但有时您最终会出现间隙(插入失败、删除等)。我发现最好使用 TOP x 结合 WHERE 来获得最接近的。
      猜你喜欢
      • 2011-10-26
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多