Concordo com Strawberry sobre o esquema. Podemos discutir ideias para um melhor desempenho e tudo mais. Mas aqui está minha opinião sobre como resolver isso depois de alguns bate-papos e alterações na pergunta.
Observe abaixo as alterações de dados para lidar com várias condições de limite que incluem livros sem imagens nessa tabela e desempates. Significado de tie-breaks usando o
max(upvotes)
. O OP mudou a pergunta algumas vezes e adicionou uma nova coluna na tabela de imagens. A pergunta modificada tornou-se return 1 linha make por livro. Raspe isso, sempre 1 linha por livro, mesmo que não haja imagens. A informação da imagem a ser retornada seria aquela com o máximo de votos positivos.
Tabela de livros
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);
Mudanças de dados da pergunta original.
Principalmente os novos
upvotes
coluna. O abaixo inclui uma linha de desempate adicionada.
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);
Visualização de uma tabela derivada
Isso é apenas para ajudar a visualizar uma parte interna da consulta final. Ele demonstra a pegadinha para situações de desempate, assim o
rownum
variável. Essa variável é redefinida para 1 cada vez que o bookid
muda, caso contrário, ele incrementa. No final (nossa consulta final) queremos apenas rownum=1
linhas para que no máximo 1 linha seja retornada por livro (se houver). Consulta final
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
Resultados
+----+---------------+---------------------+----------+
| 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 |
+----+---------------+---------------------+----------+
O significado da
cross join
é meramente introduzir e definir valores iniciais para 2 variáveis. Isso é tudo. Os resultados são os dez principais livros em ordem decrescente de
purchasecount
com as informações de images
se existir (caso contrário NULL
) para a imagem mais votada. A imagem selecionada respeita as regras de desempate escolhendo a primeira conforme mencionado acima na seção Visualização com rownum
. Considerações finais
Deixo para o OP inserir o
where
apropriado cláusula no final, pois os dados de amostra fornecidos não tinham um nome de livro útil para pesquisar. Essa parte é trivial. Ah, e faça algo sobre o esquema para a grande largura de suas chaves primárias. Mas isso é off-topic no momento.