SQL在特定行周围选择“窗口”

时间:2008-12-29 16:54:53

标签: sql mysql

很可能以前曾经问过这样的问题,但我想不出要搜索的术语。

我正在制作一个照片库应用程序,并希望显示9个缩略图,显示当前正在显示的照片的上下文(在当前照片位于中心的3x3网格中,除非当前照片在前4张中正在显示照片,在这种情况下,如果当前照片是第二张,我想要选择照片1到9)。例如,给定一张包含带有ID的照片列表的相册:

1,5,9,12,13,18,19,20,21,22,23,25,26

如果当前照片是19,我还要查看:

9,12,13,18,19,20,21,22,23

如果当前照片是5,我还要查看:

1,5,9,12,13,18,19,20,21

我一直在考虑以下几点:

SELECT *
FROM photos
WHERE ABS(id - currentphoto) < 5
ORDER BY id ASC 
LIMIT 25

但是这不适用于ids是非连续的(如上例所示),或者当前照片之前照片不足的情况。

有什么想法吗?

谢谢,

的Dom

P.S。如果有任何不清楚的地方请发表评论,我会澄清这个问题。如果有人能想到一个更有用的标题来帮助其他人将来找到这个问题,那么请评论。

3 个答案:

答案 0 :(得分:5)

可能只需使用UNION,然后在显示结果的过程代码中修剪额外的结果(因为这将在非边缘情况下返回20行):

(SELECT 
     * 
FROM photos
   WHERE ID < #current_id#
   ORDER BY ID DESC LIMIT 10)
UNION
  (SELECT *
   FROM photos
   WHERE ID >= #current_id#
   ORDER BY ID ASC LIMIT 10)
ORDER BY ID ASC
编辑:根据 le dorfier 的建议,UNION双方的限制增加到10。

编辑2:根据Dominic的建议修改以更好地反映最终实施。

答案 1 :(得分:1)

如果您使用的是SQL Server,可以使用row_number()函数为您提供行顺序索引,并执行以下操作:

declare @selected_photo integer;
set @selected_photo = 5;

declare @buffer_size integer;
set @buffer_size = 2;

select
   ph.rownum,
   ph.id
from
   (select row_number() over (order by Id) as rownum, * from Photos) as ph
where
   ph.rownum between case
                         when @selected_photo - @buffer_size < 1 then 1
                         else @selected_photo - @buffer_size
                      end
                      and @selected_photo + @buffer_size

编辑: 这是一篇关于在MySQL中模拟row_number()函数的文章,将其与 这可能会得到你所需要的 - 我会尝试它,但没有一个MySQL数据库方便在工作中使用。 : - )

http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/

答案 2 :(得分:0)

这是标准的“行排序”问题...如果您的数据库具有rowId功能,您可以使用它,否则您需要一个子查询来计算行的numnber,其Ids小于当前行的id ...就像这样:

- 假设@Id是“中间”

中id的值
 Select *  From Photos P
 Where (Select Count(*) From Photos
         Where id <= P.Id)
     Between (Select Count(*) From Photos
              Where id < @Id) - 4
        And  (Select Count(*) From Photos
              Where id < @Id) + 4

当评论提出相册问题时,您需要将相册谓词添加到每个子查询

   Select *  From Photos P
   Where (Select Count(*) From Photos
          Where album = @album
            And id <= P.Id)
     Between (Select Case When Count(*) < 4 
                      Then 4 Else Count(*) End
              From Photos
              Where album = @album
                 And id < @Id) - 4
        And  (Select Case When Count(*) < 4 
                      Then 4 Else Count(*) End
              From Photos
              Where album = @album
                  And id < @Id) + 4