2010-01-11 14 views
7

Używam kwerendy MySQL do rankingu użytkowników mojej witryny zgodnie z liczbą recenzji książek i recenzji receptury, które wnieśli. Po początkowych problemach z wieloma zapytaniami JOIN przełączyłem się na serię podzapytań, co jest znacznie, dużo szybsze. Mimo że mogę wyodrębnić liczby recenzji od każdego członka, nie mogę wymyślić, jak je dodać, aby można było sortować według łącznej liczby.Jak dodać wyniki kilku podkwerend?

Oto bieżące zapytanie:

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
FROM users 

muszę dodać razem bookreviews i recipereviews dostać "reviewtotals. MySQL nie pozwoli ci używać prostej składni do wykonywania obliczeń na aliasach, ale przypuszczam, że jest inny sposób na zrobienie tego?

+0

@mandel, jestem ciekaw waszych problemów z 'JOIN' zazwyczaj rozwiązać tego rodzaju problemu z' JOIN' - zobacz moją odpowiedź dla odniesienie. Z mojego doświadczenia wynika, że ​​jest ono zazwyczaj dużo szybsze w przypadku MySQL niż wiele podobnych podróbek. Byłbym zainteresowany, aby usłyszeć, czy w twoim przypadku rozwiązanie podkwerendy jest szybsze niż JOIN. Byłbym wdzięczny, gdybyś mógł dać mi znać. –

+0

Moje problemy z JOIN pochodziły raczej z niedoświadczenia niż z filozofii. Mój poprzedni JOIN spowodował strasznie powolne zapytanie - 9 sekund; Okazało się, że tworzy produkt kartezjański. Zapytałem o to na SO tutaj: http://stackoverflow.com/questions/2030032/is-performing-a-count-calculation-slowing-down-my-mysql-query. Kiedy zwróciłem się do podkwerend, szybkość znacznie się poprawiła, I mogłem zrozumieć, co robiłem! – mandel

+0

Zobacz moją odpowiedź na twój post dla porównania prędkości - twoje zapytanie JOIN jest trochę szybsze, ale tylko 4/100ths sekundy przy bieżącym DB wielkości. – mandel

Odpowiedz

9

Owiń ją w podkwerendzie:

SELECT *, 
     bookreviews + recipereviews AS totalreviews 
FROM (
     SELECT users.*, 
       (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
       (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
       (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
     FROM users 
     ) q 
0

Próbowałeś wykonać następujące czynności?

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    ((SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) + 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID)) as reviewtotal 
FROM users 
+0

Dzięki - to prawie wszystko, ale wciąż muszę generować sumy z bookreviews i recipereviews, a także z wyliczonej sumy. – mandel

1

dwie opcje:

Wariant 1: Brzydkie to piekło, a prawdopodobnie powolny (w zależności od pamięci podręcznej zapytań):

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) + (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as reviewtotals 
FROM users 

Opcja 2: Zapisz wyniki do tabeli tymczasowej i następnie kwerendy tej tabeli

Może to zadziała (nie próbowałem)

SELECT *, bookreviews+recipereviews as reviewtotals FROM 
(SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
FROM users) u 
+0

Numer dwa prawie działa, ale musisz dodać alias do pierwszego podkwerendy - wtedy jest to identyczne z rozwiązaniem @ Quassnoi, które było minutę wcześniej. Dzięki! – mandel

+0

Widziałem, że była inna odpowiedź podczas pisania ... –

1

Jeśli chcesz być bezpieczny i szybki, zrób to tak:

SELECT users.* 
,  titles.num       titles 
,  book_reviews.num      book_reviews 
,  recipe_reviews.num     recipe_reviews 
,  book_reviews.num + recipe_reviews.num total_reviews 
FROM  users 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  bookshelf 
      GROUP BY user_ID 
     ) as titles 
ON  users.ID = titles.user_ID 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  book_reviews 
      GROUP BY user_ID 
     ) as book_reviews 
ON  users.ID = reviews.user_ID 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  recipe_reviews 
      GROUP BY user_ID 
     ) as recipe_reviews 
ON  users.ID = recipes.user_ID 

Jeśli chcesz trzymać się podzapytania w liście SELECT, i chcesz, żeby było bezpiecznie, spójrz na rozwiązanie Quassnoi.

Jeśli chcesz żyć trochę niebezpiecznie i nadal chcesz uzyskać szybki wynik, możesz użyć zmiennych zdefiniowanych przez użytkownika. Przewiduję, to będzie bardzo bezpieczny w tym konkretnym przypadku:

SELECT users.*, 
     (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
     @bookreviews:=(
      SELECT count(*) 
      FROM book_reviews 
      WHERE book_reviews.user_id = users.ID 
     ) as bookreviews, 
     @recipereviews:=(
      SELECT count(*) 
      FROM recipe_reviews 
      WHERE recipe_reviews.user_id = users.ID 
     ) as recipereviews, 
     @bookreviews + @recipereviews as total_reviews 
FROM users 
+0

Interesujące: Opcja 1 jest odrobinę szybsza niż rozwiązanie Quassnoi (0,02 s vs 0).024 s), natomiast opcja 2 wynosi 0,88 s, a więc stosunkowo nieco wolniej. Uważam, że Quassnoi jest znacznie prostszy w kwestii czytelności (i mojego zrozumienia tego, co się dzieje). Czy korzystanie z metody JOIN w pierwszym przykładzie ma swoje zalety? – mandel

+0

mandel: tak, zalety stają się szybko widoczne, gdy zestawy, z którymi masz do czynienia, rosną. JOIN jest znacznie lepiej skalowalny. Jednak w tych czasach zegara nie sądzę, że możemy powiedzieć coś rozstrzygającego. Odrzuciłbym tak małą różnicę. Ale nadal powinieneś zobaczyć znaczne różnice, gdy dostaniesz więcej danych, którymi możesz się zająć. Rozwiązanie podkwerendy wykonuje każde podzapytanie dla każdego wiersza zewnętrznego zapytania. Łączenie w zagnieżdżone pętle jest zwykle znacznie bardziej wydajne. –

Powiązane problemy