我有两张桌子 - books
和images
。 books
包含id
,name
,releasedate
,purchasecount
等列。 images
有bookid
(与书籍中的id
相同,基本上一本书可以有多个图片。虽然我没有设置任何外键约束),bucketid
,poster
(每个记录指向某个存储桶中的图像文件,某个bookid
)。
表架构:
poster
在images
中是唯一的,因此它是主键。name
,id
,releasedate
)bookid
,poster
,bucketid
)我的查询是,给出一个名称,从书名表中找到名称与该名称相匹配的前十本书(按purchasecount
的数量排序),并为该书返回任何(最好是第一个)记录(bucketid
表格中的poster
和images
)。
显然,这可以通过运行第一个查询来解决,并使用其结果来查询图像表,但这样会很慢,所以我想使用'join'和子查询一次完成它。但是,我正在尝试的不是给我正确的结果:
select books.id,books.name,year(releasedate),purchasecount,bucketid,poster from books
inner join (select bucketid,bookid, poster from images) t on
t.bookid = books.id where name like "%foo%" order by purchasecount desc limit 2;
有人可以根据需要建议最佳查询来获取结果集(包括更改表模式以改善搜索时间的任何建议)吗?
更新了小提琴:http://sqlfiddle.com/#!9/17c5a8/1。
示例查询应返回两个结果 - fooe
和fool
,以及每个结果的一个(每个图书对应的多个海报中的任何一个)海报。但是我没有得到正确的结果。预期:
fooe - 1973 - 459 - 11 - swt
(或fooe - 1973 - 459 - 11 - pqr
)
fool - 1963 - 456 - 12 - xxx
(或fool - 1963 - 456 - 111 - qwe
)
答案 0 :(得分:1)
我同意草莓的架构。我们可以讨论提高性能的想法以及所有这些。但是,在我对这个问题进行一些聊天和更改之后,我将如何解决这个问题。
下面注意数据变化,以处理各种边界条件,包括该表中没有图像的书籍,以及打破中断。使用max(upvotes)
进行打结。 OP改变了几次问题并在图像表中添加了一个新列。
修改后的排队成为每本书返回1行。划伤一下,即使没有图像,每本书也要一行。要返回的图像信息将是具有最大upvotes的图像信息。
create table books
( id int primary key,
name varchar(1000),
releasedate date,
purchasecount int
) ENGINE=InnoDB;
insert into books values(1,"fool","1963-12-18",456);
insert into books values(2,"foo","1933-12-18",11);
insert into books values(3,"fooherty","1943-12-18",77);
insert into books values(4,"eoo","1953-12-18",678);
insert into books values(5,"fooe","1973-12-18",459);
insert into books values(6,"qoo","1983-12-18",500);
主要是新的upvotes
列。
以下内容包括添加的抢七行。
create table images
( bookid int,
poster varchar(150) primary key,
bucketid int,
upvotes int -- a new column introduced by OP
) ENGINE=InnoDB;
insert into images values (1,"xxx",12,27);
insert into images values (5,"pqr",11,0);
insert into images values (5,"swt",11,100);
insert into images values (2,"yyy",77,65);
insert into images values (1,"qwe",111,69);
insert into images values (1,"blah_blah_tie_break",111,69);
insert into images values (3,"qwqqe",14,81);
insert into images values (1,"qqawe",8,45);
insert into images values (2,"z",81,79);
这只是为了帮助可视化最终查询的内部部分。它演示了抢七局面的问题,即rownum
变量。每次bookid
更改时,该变量都会重置为1,否则会递增。最后(我们的最终查询)我们只想要rownum=1
行,以便每本书返回最多1行(如果有的话)。
select b.id,b.purchasecount,xDerivedImages2.poster,xDerivedImages2.bucketid
from books b
left join
( select i.bookid,i.poster,i.bucketid,i.upvotes,
@rn := if(@lastbookid = i.bookid, @rn + 1, 1) as rownum,
@lastbookid := i.bookid as dummy
from
( select bookid,max(upvotes) as maxup
from images
group by bookid
) xDerivedImages
join images i
on i.bookid=xDerivedImages.bookid and i.upvotes=xDerivedImages.maxup
cross join (select @rn:=0,@lastbookid:=-1) params
order by i.bookid
) xDerivedImages2
on xDerivedImages2.bookid=b.id and xDerivedImages2.rownum=1
order by b.purchasecount desc
limit 10
+----+---------------+---------------------+----------+
| id | purchasecount | poster | bucketid |
+----+---------------+---------------------+----------+
| 4 | 678 | NULL | NULL |
| 6 | 500 | NULL | NULL |
| 5 | 459 | swt | 11 |
| 1 | 456 | blah_blah_tie_break | 111 |
| 3 | 77 | qwqqe | 14 |
| 2 | 11 | z | 81 |
+----+---------------+---------------------+----------+
cross join
的重要性仅仅是引入和设置2个变量的起始值。就是这样。
结果是按purchasecount
降序排列的前十本图书,其中images
的信息是否存在(否则为NULL
),表示最受欢迎的图片。所选图像遵循上面提到的rownum
可视化部分中提到的第一个处理中断规则。
我将它留给OP,以便在最后找到适当的where
子句,因为给出的样本数据没有可用的书名来搜索。那部分是微不足道的。哦,并为主键宽度大的架构做些什么。但目前这是偏离主题的。