我有图片库。每张图片的评级都取决于有多少用户投票“我喜欢这个”。 MySQL表就像这样:
id |image |rating
------------------------------------
166 |6.png |9
165 |8.png |9
189 |1.png |8
171 |99.png |8
169 |56.png |8
155 |34.png |8
265 |7.png |7
754 |86.png |6
166 |37.png |4
342 |95.png |2
99 |35.png |0
76 |34.png |0
44 |3.png |0
8 |22.png |0
任务是:可以查看按评级排序的图库。使用ORDER BY rating DESC, id DESC
列出图像很容易,但当用户点击图像时出现问题,我必须在打开的图像旁边显示“上一张图像”和“下一张图像”按钮。
假设我们现在正在查看示例表中id = 169的图像:
id |image |rating
------------------------------------
169 |99.png |8
如何编写查询,获取上一张图片(id = 171)?问题是,主要排序是rating
(不是唯一的),辅助是唯一的id
。在任何情况下哪个查询都会给我正确的上一张图像。
我试过了:
SELECT *
FROM images
WHERE rating >= 8 AND id >=169
ORDER BY rating, id
LIMIT 1
但它没有,因为只有在评级相同时才必须检查id >=169
。
我有点困惑,请帮帮我。
更新
自己想出这个。假设我有当前记录的rating
和id
值,获取先前记录的查询将是:
SELECT *
FROM `images`
WHERE
(`rating` = 8 AND `id` > 169)
OR `rating` > 8
ORDER BY `rating`, `id`
LIMIT 1
如果未评估rating = 8 AND id > 169
,则rating > 8
会发挥作用。结果很简单。
谢谢大家!用大多数赞成票接受答案。
答案 0 :(得分:5)
SELECT * FROM images ORDER BY rating DESC, id LIMIT $n, 1
其中$n
是从0开始的计数器。按ID排序可确保后续调用始终保持相同的顺序。因此,下一张图片为$n+1
,之前是$n-1
。
此外,如果您想确保当前图像有下一张图像,您可以随时获取2张图像(用户当然不喜欢点击“下一步”以获得404错误)。
编辑:评论的新要求
嗯,您可以尝试计算与当前图像的最小距离。SELECT * from images
WHERE id < $current[id] AND rating >= $current[rating]
ORDER by ((abs($current[rating] - rating) << 32) + abs($current[id] - id))
LIMIT 1
SELECT * from images
WHERE id > $current[id] AND rating <= $current[rating]
ORDER by ((abs($current[rating] - rating) << 32) + abs($current[id] - id))
LIMIT 1
不要问我任何关于表现的事情;)
答案 1 :(得分:1)
您正在寻找一种面向游标的方法。另一个非常简单的方法是通过特定的排序条件选择所有ID,保存应用程序中的ID,然后浏览并选择使用ID和查询专门选择所需的行。
答案 2 :(得分:1)
试试这个,将test
替换为您的表名,并将curr.id =169
替换为当前页面ID
SELECT curr.id AS currid, curr.image as curr_img,
prev.id AS previd, prev.image as prev_img,
next.id AS nextid, next.image as next_img
FROM test curr
LEFT JOIN test prev
ON prev.id != curr.id
AND (
prev.rating > curr.rating
OR (
prev.rating = curr.rating
AND prev.id > curr.id
)
)
LEFT JOIN test next
ON next.id != curr.id
AND (
next.rating < curr.rating
OR (
next.rating = curr.rating
AND next.id < curr.id
)
)
WHERE curr.id =169
ORDER BY prev.rating ASC , next.rating DESC , prev.id ASC , next.id DESC
LIMIT 1
答案 3 :(得分:0)
获取一个查询中的所有条目,将其放入php数组中,然后使用它!
答案 4 :(得分:0)
我记得我在MySQL性能博客上读到的一篇关于pagination的文章,并将这个例子打破了,这可能证明是有帮助的(@row_id是多余的)
drop table if exists gallery;
create table gallery
(
id int unsigned not null,
image varchar(255) not null,
rating tinyint unsigned default 0
)
engine=innodb;
insert into gallery values
(166,'6.png',9),(165,'8.png',9),(189,'1.png',8),
(171,'99.png',8),(169,'56.png',8),(155,'34.png',8),
(265,'7.png',7),(754,'86.png',6),(37,'37.png',4),
(342,'95.png',2),(99 ,'35.png',0),(76 ,'34.png',0),
(44 ,'3.png',0),(8 ,'22.png',0), (1001 ,'1001.png',0);
drop procedure if exists list_gallery_paged;
delimiter #
create procedure list_gallery_paged
(
in p_last_id int unsigned,
in p_last_rating tinyint unsigned
)
proc_main:begin
set @row_id = 0;
if p_last_id <= 0 then
select @row_id:=@row_id+1 as row_id, g.*
from gallery g order by rating desc, id desc limit 4;
else
select @row_id:=@row_id+1 as row_id, g2.*
from gallery g inner join gallery g2 on g.id = g2.id
where
g.rating <= p_last_rating and (g.id < p_last_id or g.rating < p_last_rating)
order by
g.rating desc, g.id desc limit 4;
end if;
end proc_main #
delimiter ;
-- in pages of 4 (use all rows)
select g.* from gallery g order by rating desc, id desc;
call list_gallery_paged(0,0);
call list_gallery_paged(171,8);
call list_gallery_paged(754,6);
call list_gallery_paged(99,0);
call list_gallery_paged(8,0);
-- one at a time (use top row only)
select g.* from gallery g order by rating desc, id desc;
call list_gallery_paged(265,7);
call list_gallery_paged(754,6);
call list_gallery_paged(37,4);
call list_gallery_paged(342,2);
call list_gallery_paged(1001,0);
call list_gallery_paged(99,0);
call list_gallery_paged(76,0);
call list_gallery_paged(44,0);
call list_gallery_paged(8,0);