2014-06-05 9 views
5

Gibt es eine Möglichkeit, nach einem eindeutigen (primären) Schlüssel zu gruppieren, was im Wesentlichen eine implizite Garantie dafür liefert, dass die anderen Spalten aus dieser Tabelle wohldefiniert sind?GROUP BY nur Primärschlüssel, aber andere Werte auswählen

SELECT myPrimaryKey, otherThing 
FROM myTable 
GROUP BY myPrimaryKey 

Ich weiß, dass ich die anderen Spalten die Erklärung hinzufügen (GROUP BY myPrimaryKey,otherThing), aber ich versuche, das zu vermeiden. Wenn Sie neugierig sind, warum, lesen Sie weiter:


ich eine Aussage haben, die im wesentlichen dies tut:

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 

der gut arbeitet, ist aber ein bisschen langsam in MySQL. Wenn ich nodes.node_label aus dem GROUP BY entferne, läuft es etwa 10x schneller (laut EXPLAIN, dies ist, weil einer der früheren Joins beginnt, einen Index zu verwenden, wenn es zuvor nicht getan hat).

Wir sind im Prozess Postgres migrieren, so dass alle neuen Aussagen sollen mit beide MySQL und Postgres, wenn möglich, kompatibel sein. Jetzt in Postgres, die ursprüngliche Anweisung läuft schnell, aber die neue Anweisung (mit der reduzierten Gruppe von) wird nicht ausgeführt (weil Postgres strenger ist). In diesem Fall ist es ein falscher Fehler, da die Anweisung tatsächlich gut definiert ist.

Gibt es eine Syntax, die ich verwenden kann, die die gleiche Anweisung in beiden Plattformen ausgeführt wird, während MySQL nur eine Spalte in der Gruppe für Geschwindigkeit verwenden?

+3

'In diesem Fall ist es ein falscher Fehler, weil die Aussage eigentlich gut defined.' ist Nein nein nein, MySql akzeptiert Weirds Dinge für GROUP BY (mit unvorhersehbaren Ergebnissen), alle anderen DBMS zwingen Sie zu vorhersehbaren Ergebnissen (was normalerweise nützlich ist). Um eine Lösung zu finden, würde ich lieber an der Indexverwaltung arbeiten, um MySql Langsamkeit zu vermeiden! –

+0

@ RaphaëlAlthaus normalerweise das stimmt, aber die Gruppierung nach dem Primärschlüssel (oder irgendeinem 'UNIQUE'-Schlüssel) stellt sicher, dass alle anderen Werte in der gleichen Tabelle gut definiert sind. – Dave

+0

aber ich bezweifle, dass es so ein dbms funktioniert. Ich denke nicht, dass das Abfrage-Scannen und Parsing nach Primärschlüsseln/eindeutigen Schlüsseln sucht. Das kommt nach (Abfrageoptimierung/Ausführungsstrategie) ... –

Antwort

0

Sie könnten versuchen, die anderen Spalten in Aggregate Umwandlung:

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

Ich mag diesen Trick, und ich werde es für jetzt verwenden. Aber wie Richard Huxton sagte, ist das Verhalten, das ich suche, in Postgres 9.1+ erlaubt, also werde ich als dauerhafte Lösung darum bitten, die Testdatenbank auf den neuesten Stand zu bringen. – Dave

+0

WAS SOLLTE GETAN WERDEN, WENN ICH NUR PRIMÄRSCHLÜSSEL PROJEKTIEREN MUSS? –

1

In Postgres (nicht in MySQL, obwohl), könnten Sie DISTINCT ON verwenden, um einen Pick einzelne, konsistente Zeile pro Wert (oder eine Gruppe von Werte), ohne sie zu aggregieren:

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) 

dass Sie eine einzelne, willkürliche Zeile für jede node_id gibt. zu einer bestimmten Zeile auswählen, hinzufügen:

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

.. mehr ORDER BY Elemente hinzufügen eine bestimmte Zeile zu holen. Details:
Select first row in each GROUP BY group?

0

In neueren Versionen von MySQL Sie sql_mode=only_full_group_by aktiviert haben könnte, die nicht wählen erlaubt Spalten nicht aggregierte wenn group by Verwendung dh es Sie zwingt, eine Funktion wie max() oder avg() oder group_concat() zu verwenden, manchmal Sie wollen nur einen Wert.

Dieses Flag ist in MySql 5.7 standardmäßig aktiviert.

Die Funktion any_value() ist verfügbar, wenn dieses Flag aktiviert ist.

Sie können den gleichen Effekt erzielen, ohne ONLY_FULL_GROUP_BY zu deaktivieren unter Verwendung ANY_VALUE() an die nicht aggregierten Spalte zu verweisen.

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

Weitere Informationen hier: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by und hier: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html