Estoy de acuerdo con Strawberry sobre el esquema. Podemos discutir ideas para un mejor rendimiento y todo eso. Pero aquí está mi opinión sobre cómo resolver esto después de algunos chats y cambios en la pregunta.
Tenga en cuenta a continuación los cambios de datos para hacer frente a varias condiciones límite que incluyen libros sin imágenes en esa tabla y desempates. Desempates significado usando el max(upvotes)
. El OP cambió la pregunta varias veces y agregó una nueva columna en la tabla de imágenes.
La pregunta modificada se convirtió en devolución de 1 fila por libro. Tacha eso, siempre 1 fila por libro aunque no haya imágenes. La información de la imagen a devolver sería la que tenga el máximo de votos a favor.
Mesa de libros
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);
Cambios en los datos de la pregunta original.
Principalmente los nuevos upvotes
columna.
A continuación se incluye una fila de desempate agregada.
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);
Visualización de una tabla derivada
Esto es solo para ayudar a visualizar una parte interna de la consulta final. Demuestra el gotcha para situaciones de desempate, por lo tanto, el rownum
variable. Esa variable se restablece a 1 cada vez que bookid
cambia de lo contrario se incrementa. Al final (nuestra consulta final) solo queremos rownum=1
filas para que se devuelva un máximo de 1 fila por libro (si corresponde).
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 |
+----+---------------+---------------------+----------+
El significado de la cross join
es simplemente introducir y establecer valores iniciales para 2 variables. Eso es todo.
Los resultados son los diez libros principales en orden descendente de purchasecount
con la información de images
si existe (de lo contrario NULL
) para la imagen más votada. La imagen seleccionada respeta las reglas de desempate eligiendo la primera como se mencionó anteriormente en la sección Visualización con rownum
.
Reflexiones finales
Le dejo al OP encajar en el where
apropiado cláusula al final ya que los datos de muestra dados no tenían un nombre de libro útil para buscar. Esa parte es trivial. Ah, y haz algo con el esquema para el gran ancho de tus claves primarias. Pero eso está fuera de tema en este momento.