SQL在特定行周围选择“窗口”
Posted
技术标签:
【中文标题】SQL在特定行周围选择“窗口”【英文标题】:SQL Selecting "Window" Around Particular Row 【发布时间】:2008-12-29 16:54:52 【问题描述】:以前很可能有人问过这样的问题,但我想不出要搜索的字词。
我正在开发一个照片库应用程序,并希望显示 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
但这不适用于 id 不连续的情况(如上面的示例),或者当前照片之前的照片不足的情况。
有什么想法吗?
谢谢,
Dom
附言如果有任何不清楚的地方,请发表评论,我会澄清这个问题。如果有人能想到一个更有用的标题来帮助其他人将来找到这个问题,那么也请发表评论。
【问题讨论】:
【参考方案1】:可能只使用一个 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 的建议进行修改以更好地反映最终实现。
【讨论】:
这是一个很好的、有用的技术。我过去曾将它与 mysql 一起使用。要处理列表的末尾,您将没有足够的行:使用 LIMIT 10 并在程序代码中计算出选择。 感谢 le dorfier,解决了限制问题,我会按照建议进行编辑。 我最终做了与此非常相似的事情。我在 UNION 的结果上添加了“ORDER BY id ASC”,因此行按预期返回。您需要将第一个 ORDER 更改为 id DESC,否则前几行将始终返回。【参考方案2】:如果您使用的是 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/
【讨论】:
谢谢 Ron - 但我使用的是 MySQL,所以我认为我不能使用它 - 可以吗? 我在 MySQL 文档中没有看到任何类似的东西......但我会继续探索。 :-) @RonSavage:别打扰。 MySQL 是少数不支持窗口函数的 DBMS 之一。【参考方案3】:这是标准的“行排序”问题...如果您的数据库具有 rowId 功能,您可以使用它,否则您需要一个子查询来计算 ID 小于当前行 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
【讨论】:
按专辑应该有额外的过滤器,否则不能解决问题 - 即它只适用于顺序 id。以上是关于SQL在特定行周围选择“窗口”的主要内容,如果未能解决你的问题,请参考以下文章