2011-08-22 22 views
7

Mam system listy obserwowanych, które zakodowałem, w przeglądzie listy obserwowanych użytkowników, zobaczyliby listę rekordów, jednak lista pokazuje duplikaty, gdy w bazie danych pokazuje tylko dokładna, prawidłowa liczba.GROUP BY nie usuwa duplikatów

Próbowałem GROUP BY watch.watch_id, GROUP BY rec.record_id, żaden z typów grupy, których próbowałem, nie usunął duplikatów. Nie jestem pewien, co robię źle.

SELECT watch.watch_date, 
     rec.street_number, 
     rec.street_name, 
     rec.city, 
     rec.state, 
     rec.country, 
     usr.username 
FROM 
(
    watchlist watch 

    LEFT OUTER JOIN records rec ON rec.record_id = watch.record_id 

    LEFT OUTER JOIN members usr ON rec.user_id = usr.user_id 
) 
WHERE watch.user_id = 1 
GROUP BY watch.watch_id 
LIMIT 0, 25 

na liście obserwowanych tabela wygląda następująco:

+----------+---------+-----------+------------+ 
| watch_id | user_id | record_id | watch_date | 
+----------+---------+-----------+------------+ 
|  13 |  1 |  22 | 1314038274 | 
|  14 |  1 |  25 | 1314038995 | 
+----------+---------+-----------+------------+ 

Odpowiedz

17

GROUP BY nie "usunąć duplikaty". GROUP BY pozwala na agregację. Jeśli chcesz tylko połączyć zduplikowane wiersze, użyj SELECT DISTINCT.

Jeśli chcesz połączyć wiersze, które są duplikowane w niektórych kolumnach, użyj GROUP BY, ale musisz określić, co zrobić z innymi kolumnami. Możesz je pominąć (nie wymieniając ich w klauzuli SELECT) lub agregować (używając funkcji takich jak SUMA, MIN i AVG). Na przykład:

SELECT watch.watch_id, COUNT(rec.street_number), MAX(watch.watch_date) 
... GROUP by watch.watch_id 

EDIT

PO poprosił o wyjaśnienia.

Weź pod uwagę "widok" - wszystkie dane zebrane przez FROMy i DOŁĄCZY i GDZIE - wywołaj V. Są dwie rzeczy, które możesz chcieć zrobić.

Po pierwsze, można mieć całkowicie zduplikowane wiersze które chcesz połączyć:

a b c 
- - - 
1 2 3 
1 2 3 
3 4 5 

Następnie wystarczy użyć DISTINCT

SELECT DISTINCT * FROM V; 

a b c 
- - - 
1 2 3 
3 4 5 

Albo, możesz mieć częściowo zduplikowane wiersze że chcesz połączyć:

a b c 
- - - 
1 2 3 
1 2 6 
3 4 5 

Te pierwsze dwa wiersze są w pewnym sensie "takie same", ale wyraźnie różne w innym znaczeniu (w szczególności, powinny być łączone za pomocą SELECT DISTINCT). Musisz zdecydować, jak je połączyć. Możesz odrzucić kolumnę c jako nieistotną:

SELECT DISTINCT a,b FROM V; 

a b 
- - 
1 2 
3 4 

Możesz też przeprowadzić na nich agregację. Można dodawać je:

SELECT a,b, SUM(c) "tot" FROM V GROUP BY a,b; 

a b tot 
- - --- 
1 2 9 
3 4 5 

można dodać wybrać najmniejszą wartość:

SELECT a,b, MIN(c) "first" FROM V GROUP BY a,b; 

a b first 
- - ----- 
1 2 3 
3 4 5 

Albo można podjąć średniej (AVG), odchylenie standardowe (STD), a każda z bandą innych funkcji, które pobierają kilka wartości dla c i łączą je w jedno.

To, co nie jest opcją, to po prostu nie robić nic. Jeśli po prostu wylistujesz niezgrupowane kolumny, DBMS albo zgłosi błąd (Oracle to zrobi - właściwy wybór, imo) albo wybierze jedną wartość mniej więcej losowo (MySQL). Ale jako Dr.Peart powiedział: "Kiedy zdecydujesz się nie decydować, wciąż masz wybór."

+0

Przepraszam, czy możesz wyjaśnić nieco więcej przy agregowaniu. – MacMac

+0

Widzę, jedno pytanie, jak można wybrać kolumny z 'DISTINCT' zamiast robić' DISTINCT * '. – MacMac

+0

Ponownie przeczytaj. W mojej odpowiedzi jest już przykład. – Malvolio

0

Grupujesz według numeru watch.watch_id i masz dwa wyniki, które mają różne identyfikatory zegarków, więc naturalnie nie będą grupowane.

Również z wyświetlanych wyników mają różne rekordy. To wygląda jak idealnie uzasadnione oczekiwane rezultaty. Jeśli próbujesz wybrać tylko różne wartości, nie chcesz mieć grupy, ale chcesz wybrać różne wartości.

SELECT DISTINCT() ...

3

Podczas SELECT DISTINCT może rzeczywiście działać w Twoim przypadku, ważne jest, aby pamiętać, dlaczego to, co masz nie działa.

Wybieracie pola znajdujące się poza GROUP BY. Chociaż MySQL pozwala na to, dokładne wiersze, które zwraca dla pól innych niż GROUP BY, są niezdefiniowane.

Jeśli chciał zrobić z GROUP BY spróbować czegoś więcej tak:

SELECT watch.watch_date, 
     rec.street_number, 
     rec.street_name, 
     rec.city, 
     rec.state, 
     rec.country, 
     usr.username 
FROM 
(
    watchlist watch 

    LEFT OUTER JOIN est8_records rec ON rec.record_id = watch.record_id 

    LEFT OUTER JOIN est8_members usr ON rec.user_id = usr.user_id 
) 
WHERE watch.watch_id IN (
SELECT watch_id FROM watch WHERE user_id = 1 
GROUP BY watch.watch_id) 
LIMIT 0, 25 
+0

Otrzymuję 'Ta wersja MySQL jeszcze nie obsługuje 'LIMIT i IN/ALL/ANY/SOME subquery''. – MacMac

+0

Przepraszam, miałem zamiar umieścić to poza podzapytaniem. Zobacz aktualizację. –

0

Jeśli powiesz tabela obserwowanych jest wyjątkowy, a następnie jeden (lub oba) z innych tabel (a) ma duplikaty lub (b) nie jest unikalny dla klucza, którego używasz.

Aby stłumić duplikaty w wynikach, użyj DISTINCT jak mówi @Laykes lub spróbuj

GROUP BY watch.watch_date, 
     rec.street_number, 
     rec.street_name, 
     rec.city, 
     rec.state, 
     rec.country, 
     usr.username 

To rodzaj brzmi jak można oczekiwać wszystkie 3 stoły być unikalne ich kluczy, choć. Jeśli tak jest, po prostu ukrywasz inny problem z SQL, próbując odzyskać różne wartości.

1

Nigdy nie polecałbym używania SELECT DISTINCT, to jest bardzo powolne w przypadku dużych zestawów danych.

Spróbuj użyć rzeczy takich jak EXISTS.