1

我有两张桌子 -booksimages. booksid, name, releasedate,purchasecount等列 imagesbookid(和book里的一样id,基本上一本书可以有多张图片,虽然我没有设置任何外键约束),,,bucketidposter每条记录指向某个bucket中的一个图片文件,对于某一个bookid)。

表架构:

  1. poster在 中是唯一的images,因此它是主键。
  2. 书籍封面索引:( name, id, releasedate)
  3. 图像覆盖指数:( bookid, poster, bucketid)

purchasecount我的查询是,给定一个名称,从 books 表中找到名称与该名称匹配的前十本书(按数量排序),然后对于该书,从表中返回任何(最好是第一条)记录(bucketidposterimages

显然,这可以通过运行第一个查询并使用其结果查询图像表来解决这两个查询,但这会很慢,所以我想一次性使用“加入”和子查询来完成。但是,我正在尝试并没有给我正确的结果:

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 。

示例查询应返回两个结果 -fooefool,以及每个结果的一个(与每本书对应的多个海报中的任何一个)海报。但是我没有得到正确的结果。预期的:

fooe - 1973 - 459 - 11 - swt(或fooe - 1973 - 459 - 11 - pqr

fool - 1963 - 456 - 12 - xxx(或fool - 1963 - 456 - 111 - qwe

4

1 回答 1

1

我同意草莓关于模式的看法。我们可以讨论提高性能的想法等等。但是,在经过几次聊天和对问题的更改后,这是我对如何解决此问题的看法。

请注意下面的数据更改以处理各种边界条件,其中包括该表中没有图像的书籍和抢七。使用max(upvotes). OP 更改了几次问题并在图像表中添加了一个新列。

修改后的问题变为每本书返回 1 行。从头开始,即使没有图像,也总是每本书 1 行。要返回的图像信息将是获得最多支持的图像信息。

书桌

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个变量的起始值。就这些。

结果是按降序排列的前 10 本书,purchasecount其中的信息来自images是否存在(否则NULL)对于最受好评的图像。所选择的图像尊重抢七规则,如上面在可视化部分中提到的第一个规则rownum

最后的想法

我把它留给 OP 在where最后插入适当的子句,因为给出的示例数据没有有用的书名可供搜索。那部分是微不足道的。哦,对大宽度主键的模式做一些事情。但这目前是题外话。

于 2016-06-09T14:08:04.633 回答