2014-06-05 15 views
5

Czy istnieje sposób grupowania według klucza unikatowego (podstawowego), w zasadzie dając domyślną gwarancję, że inne kolumny z tej tabeli będą dobrze zdefiniowane?GROUP PRZEZ tylko klucz podstawowy, ale wybierz inne wartości.

SELECT myPrimaryKey, otherThing 
FROM myTable 
GROUP BY myPrimaryKey 

wiem, że mogę dodać inne kolumny do rachunku (GROUP BY myPrimaryKey,otherThing), ale staram się uniknąć. Jeśli jesteś ciekaw, dlaczego, czytaj dalej:


Mam oświadczenie, które jest w zasadzie to robi:

SELECT nodes.node_id, nodes.node_label, COUNT(1) 
FROM {a couple of joined tables} 
INNER JOIN nodes USING (node_id) 
GROUP BY nodes.node_id, nodes.node_label 

które działa prawidłowo, ale jest nieco powolny w MySQL. Jeśli usuniemy nodes.node_label z GROUP BY, będzie on działał około 10 razy szybciej (zgodnie z EXPLAIN, dzieje się tak dlatego, że jedno z wcześniejszych sprzężeń rozpoczyna indeksowanie, gdy wcześniej nie było).

Jesteśmy w procesie migracji do PostgreSQL, więc wszystkie nowe oświadczenia mają być kompatybilne z zarówno MySQL i Postgres jeśli to możliwe. Teraz w Postgresie oryginalna instrukcja działa szybko, ale nowa instrukcja (ze zmniejszoną grupą o) nie zostanie uruchomiona (ponieważ Postgres jest ostrzejszy). W tym przypadku jest to błąd fałszywy, ponieważ instrukcja jest właściwie zdefiniowana.

Czy istnieje składnia, której mogę użyć, która pozwoli uruchomić tę samą instrukcję na obu platformach, jednocześnie pozwalając MySQL używać tylko jednej kolumny w grupie przez prędkość?

+3

'W tym przypadku jest to błąd, ponieważ fałszywe oświadczenie jest rzeczywiście dobrze defined.' No no no, MySQL akceptuje weirds rzeczy dla GROUP BY (z nieprzewidywalnymi wynikami), wszystkie inne DBMS zmuszają cię do uzyskania przewidywalnych wyników (co jest zwykle przydatne). Aby znaleźć rozwiązanie, wolę pracować nad zarządzaniem indeksami, aby uniknąć spowolnienia MySql! –

+0

@ RaphaëlAlthaus zazwyczaj jest to prawda, ale grupowanie według klucza podstawowego (lub dowolnego klawisza 'UNIQUE') zapewnia, że ​​wszystkie inne wartości w tej samej tabeli są dobrze zdefiniowane. – Dave

+0

, ale wątpię, że tak działa dbms. Nie sądzę, aby skanowanie zapytań i analizowanie parsowania dla kluczy podstawowych/kluczy unikalnych. To przychodzi później (optymalizacja zapytania/strategia wykonywania) ... –

Odpowiedz

0

Można spróbować konwersji innych kolumn do agregatów:

SELECT myPrimaryKey, MAX(otherThing) 
FROM myTable 
GROUP BY myPrimaryKey 
+0

Podoba mi się ta sztuczka i na razie będę z niej korzystać. Jednak, jak wskazał RichardHuxton, zachowanie, którego szukam, jest dozwolone w Postgres 9.1+, więc jako bardziej trwałe rozwiązanie poproszę o zaktualizowanie testowej bazy danych. – Dave

+0

CO NALEŻY ZROBIĆ, GDY MUSZĘ PROJEKTOWAĆ TYLKO PIERWOTNY KLUCZ? –

1

W PostgreSQL (nie w MySQL, choć), można wykorzystać DISTINCT ON aby wybrać pojedynczy, zgodny wiersz na wartość (lub grupy wartości) bez ich agregowania:

SELECT DISTINCT ON (n.node_id) 
     *     -- select any or all columns of all joined tables 
FROM {a couple of joined tables} 
JOIN nodes n USING (node_id) 

to daje jeden, dowolny wiersz dla każdego node_id. aby wybrać konkretny wiersz, dodać:

ORDER BY n.node_id, ... -- what to sort first? 

.. dodać więcej ORDER BY przedmioty wybrać konkretny wiersz. Szczegóły:
Select first row in each GROUP BY group?

0

W nowszych wersjach MySQL można mieć sql_mode=only_full_group_by włączony która nie pozwala, aby wybrać kolumny nie agregowane przy użyciu group by tj zmusza cię do korzystania z funkcji jak max() lub avg() lub group_concat(), czasami po prostu chcesz mieć jakąkolwiek wartość.

Ta flaga jest domyślnie włączona w MySql 5.7.

Funkcja any_value() jest dostępna, gdy flaga jest włączona.

Można osiągnąć ten sam efekt bez wyłączania ONLY_FULL_GROUP_BY za pomocą ANY_VALUE(), aby zapoznać się z kolumny nonaggregated.

select t.index, any_value(t.insert_date) 
from my_table t 
group by t.index; 

Więcej informacji tutaj: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by i tutaj: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html