Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Formułowanie złożonego podzapytania MySQL

Zgadzam się z Strawberry co do schematu. Możemy omawiać pomysły na lepszą wydajność i to wszystko. Ale oto moje podejście do tego, jak rozwiązać ten problem po kilku rozmowach i zmianach w pytaniu.

Zwróć uwagę na zmiany danych poniżej, aby poradzić sobie z różnymi warunkami brzegowymi, które obejmują książki bez obrazów w tej tabeli i tie-breaki. Znaczenie tie-breaków przy użyciu max(upvotes) . OP kilka razy zmienił pytanie i dodał nową kolumnę w tabeli obrazów.

Zmodyfikowane pytanie stało się zwrotem 1 wiersza make na książkę. Zdrap to, zawsze 1 wiersz na książkę, nawet jeśli nie ma obrazów. Informacja o obrazie do zwrócenia to ta z maksymalną liczbą głosów za.

Tabela książek

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);

Zmiany danych w stosunku do pierwotnego pytania.

Głównie nowe upvotes kolumna.

Poniżej znajduje się dodany wiersz tie-break.

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);

Wizualizacja tabeli pochodnej

Ma to tylko pomóc w wizualizacji wewnętrznego elementu końcowego zapytania. Pokazuje gotcha w sytuacjach tie-breaków, stąd rownum zmienny. Ta zmienna jest resetowana do 1 za każdym razem, gdy bookid zmienia się w przeciwnym razie zwiększa się. Na koniec (nasze ostatnie zapytanie) chcemy tylko rownum=1 wierszy, tak aby na książkę zwracany był maksymalnie 1 wiersz (jeśli istnieje).

Ostateczne zapytanie

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

Wyniki

+----+---------------+---------------------+----------+
| 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 |
+----+---------------+---------------------+----------+

Znaczenie cross join jest jedynie wprowadzenie i ustawienie wartości początkowych dla 2 zmiennych. To wszystko.

Wynikiem jest dziesięć najlepszych książek w porządku malejącym od purchasecount z informacjami z images jeśli istnieje (w przeciwnym razie NULL ) w przypadku obrazu z największą liczbą głosów. Wybrany obraz przestrzega reguł tie-break, wybierając pierwszy, jak wspomniano powyżej w sekcji Wizualizacja za pomocą rownum .

Ostateczne myśli

Zostawiam OP, aby zaklinował się w odpowiednim where na końcu, ponieważ podane przykładowe dane nie zawierały użytecznej nazwy książki do wyszukania. Ta część jest banalna. Aha, i zrób coś ze schematem dla dużej szerokości twoich kluczy podstawowych. Ale w tej chwili jest to nie na temat.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wybierz sekwencję między dwiema liczbami w MySQL

  2. Najważniejsze błędy, których należy unikać podczas replikacji MySQL

  3. Zapytanie MySQL, aby znaleźć najbardziej podobny wiersz liczbowy

  4. NHibernate Nie można przekonwertować wartości daty/godziny MySQL na System.DateTime

  5. Jak równoczesne zapytania są obsługiwane w bazie danych MySQL?