Souhlasím s Strawberry ohledně schématu. Můžeme diskutovat o nápadech na lepší výkon a tak. Ale tady je můj názor na to, jak to vyřešit po několika chatech a změnách v otázce.
Všimněte si níže uvedených změn dat, které se týkají různých hraničních podmínek, které zahrnují knihy bez obrázků v této tabulce a tie-breaky. Tie-break znamená použití max(upvotes)
. OP několikrát změnil otázku a přidal nový sloupec do tabulky obrázků.
Upravená otázka se změnila na návrat 1 řádek značky na knihu. Seškrábněte to, vždy 1 řádek na knihu, i když tam nejsou žádné obrázky. Informace o obrázku, které se mají vrátit, budou ty s maximálním počtem hlasů pro.
Tabulka knih
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);
Změny dat oproti původní otázce.
Hlavně nové upvotes
sloupec.
Níže je přidána řada tie-breaku.
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);
Vizualizace odvozené tabulky
To je jen pro pomoc při vizualizaci vnitřní části konečného dotazu. To demonstruje gotcha pro tie-break situace, tedy rownum
variabilní. Tato proměnná je resetována na 1 pokaždé, když bookid
změní se jinak se zvýší. Nakonec (náš poslední dotaz) chceme pouze rownum=1
řádků tak, aby byl vrácen max. 1 řádek na knihu (pokud existuje).
Konečný dotaz
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
Výsledky
+----+---------------+---------------------+----------+
| 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 |
+----+---------------+---------------------+----------+
Význam cross join
je pouze zavést a nastavit počáteční hodnoty pro 2 proměnné. To je vše.
Výsledky jsou prvních deset knih v sestupném pořadí podle purchasecount
s informacemi z images
pokud existuje (jinak NULL
) pro obrázek s nejvyšším počtem hlasů. Vybraný obrázek dodržuje pravidla tie-breaku, která vybírá první, jak je uvedeno výše v sekci Vizualizace s rownum
.
Poslední myšlenky
Nechávám na OP, aby zaklínil příslušné where
klauzule na konci, protože uvedená ukázková data neobsahovala žádný užitečný název knihy, ve kterém by se dalo hledat. Ta část je triviální. Jo a udělejte něco se schématem pro velkou šířku vašich primárních klíčů. Ale to je v tuto chvíli mimo téma.