33 Stimmen

Ist SQL GROUP BY ein Konstruktionsfehler?

Warum muss ich in SQL angeben, nach welchen Attributen gruppiert werden soll? Warum kann es nicht einfach alle Nicht-Aggregate verwenden?

Wenn ein Attribut nicht aggregiert ist und nicht in der GROUP BY Klausel dann nicht-deterministische Wahl wäre die einzige Option unter der Annahme, dass Tupel ungeordnet sind (mysql Art tut dies) und das ist eine riesige gotcha. Soweit ich weiß, erfordert Postgresql, dass alle Attribute, die nicht in der GROUP BY aggregiert werden, was sie als überflüssig erscheinen lässt.

  • Übersehe ich etwas oder ist dies ein Fehler im Sprachdesign, der lockere Implementierungen fördert und Abfragen schwieriger zu schreiben macht?
  • Wenn ich etwas übersehe, was ist eine Beispielabfrage, wo Gruppenattribute nicht abgeleitet werden können?

17 Stimmen

Wir werden Ihre Bedenken an das ANSI SQL Committee weiterleiten.

5 Stimmen

Hehe. Das ist die Sache. Es wurde von einigen sehr klugen Leuten entworfen, also muss es etwas geben, das ich nicht sehe.

0 Stimmen

Das sage ich schon seit langem.

14voto

John Ormerod Punkte 156

Sie müssen nicht nach genau der gleichen Sache gruppieren, die Sie auswählen, z. B. :

SQL:select priority,count(*) from rule_class
group by priority

PRIORITY   COUNT(*)
      70          1
      50          4
      30          1
      90          2
      10          4

SQL:select decode(priority,50,'Norm','Odd'),count(*) from rule_class
group by priority

DECO   COUNT(*)
Odd           1
Norm          4
Odd           1
Odd           2
Odd           4

SQL:select decode(priority,50,'Norm','Odd'),count(*) from rule_class
group by decode(priority,50,'Norm','Odd')

DECO   COUNT(*)
Norm          4
Odd           8

3 Stimmen

Ja, natürlich. Alle nicht aggregierten Attribute in der SELECT müssen in der GROUP BY erscheinen, aber nicht alle Attribute in der GROUP BY müssen in der SELECT erscheinen. Ich komme mir dumm vor, weil ich den umgekehrten Fall nicht überprüft habe. Aber es gibt immer noch einen Grund, GROUP BY optional zu machen, wenn eine Mischung aus aggregierten und nicht aggregierten SELECT-Spalten vorhanden ist, ein häufiger Anwendungsfall. Ich hasse das Verhalten von Mysql, das einfach willkürlich eine Spalte auswählt, wenn das SELECT-Attribut nicht im GROUP BY berücksichtigt wird.

0 Stimmen

Äh, ich meine, wenn mysql einfach ein beliebiges Tupel auswählt.

6voto

ypercubeᵀᴹ Punkte 109378

Es gibt einen weiteren Grund für Warum muss ich in SQL angeben, nach welchen Attributen gruppiert werden soll?

Lets sat haben wir zwei einfache Tabellen: friend y car , wo wir Informationen über unsere Freunde und ihre Autos speichern.

Und nehmen wir an, wir wollen die Daten aller unserer Freunde (aus der Tabelle friend ) und für jeden unserer Freunde, wie viele Autos sie jetzt besitzen, verkauft haben, verunfallt sind und die Gesamtzahl. Oh, und wir wollen die Älteren zuerst, die Jüngeren zuletzt.

Wir würden so etwas tun wie:

SELECT f.id
     , f.firstname
     , f.lastname
     , f.birthdate
     , COUNT(NOT c.sold AND NOT c.crashed) AS owned
     , COUNT(c.sold) AS sold
     , COUNT(c.crashed) AS crashed
     , COUNT(c.friendid) AS totalcars
FROM friend f
LEFT JOIN car c     <--to catch (shame!) those friends who have never had a car 
  ON f.id = c.friendid
GROUP BY f.id
       , f.firstname
       , f.lastname
       , f.birthdate
ORDER BY f.birthdate DESC

Aber brauchen wir wirklich all diese Felder in der GROUP BY ? Ist nicht jeder Freund auf einzigartige Weise durch seine id ? Mit anderen Worten, sind nicht die firstname, lastname and birthdate funktionell abhängig von der f.id ? Warum nicht einfach tun (wie wir in MySQL können):

SELECT f.id
     , f.firstname
     , f.lastname
     , f.birthdate
     , COUNT(NOT c.sold AND NOT c.crashed) AS owned
     , COUNT(c.sold) AS sold
     , COUNT(c.crashed) AS crashed
     , COUNT(c.friendid) AS totalcars
FROM friend f
LEFT JOIN car c     <--to catch (shame!) those friends who have never had a car 
  ON f.id = c.friendid
GROUP BY f.id
ORDER BY f.birthdate 

Und was wäre, wenn wir 20 Felder in der SELECT (plus ORDER BY ) Teile? Ist die zweite Abfrage nicht kürzer, klarer und wahrscheinlich schneller (in den RDBMS, die sie akzeptieren)?

Ich sage ja. Sagen also die SQL 1999 und 2003 Spezifikationen, wenn dieser Artikel korrekt ist: Entlarvung von Mythen über Gruppen

4 Stimmen

Die neuesten SQL-Standards besagen, dass Sie Spalten in die SELECT-Liste aufnehmen können, die nicht in der GROUP BY-Liste enthalten sind, wenn diese Spalten funktional von Spalten abhängig sind, die sind in der Liste GROUP BY. Die Einwände gegen MySQL haben in der Regel damit zu tun, dass es Ihnen erlaubt, Spalten in die SELECT-Liste aufzunehmen, die funktional nicht von den Spalten in der GROUP BY-Liste abhängig sind.

0 Stimmen

@Catcall: Ich stimme dem zu. Die Abweichung von MySQL und die "zufälligen" Zeilen, die es holt, wenn man diese "Funktion" verwendet, öffnet die Tür zu Problemen.

0 Stimmen

@MikeSherrill'CatRecall' Ich habe nach einem solchen Standard gesucht. Hätten Sie einen Link? Ich habe zumindest in ANSI 1992 nichts gefunden, was vorschreibt, dass alle Spalten nach irgendetwas gruppiert werden müssen.

3voto

Antony Koch Punkte 2013

Ich würde sagen, wenn Sie eine große Anzahl von Elementen in der Gruppe von Klausel haben, dann vielleicht die Kerninfo sollte in eine tabellarische Unterabfrage, die Sie innere Join in gezogen werden.

Dies ist zwar mit einem Leistungseinbruch verbunden, sorgt aber für einen saubereren Code.

select  id, count(a), b, c, d
from    table
group by
        id, b, c, d

wird

select  id, myCount, b, c, d
from    table t
        inner join (
            select id, count(*) as myCount
            from table
            group by id
        ) as myCountTable on myCountTable.id = t.id

Dennoch bin ich daran interessiert, Gegenargumente zu hören, die dafür sprechen, dies zu tun, anstatt eine große Gruppe nach einer Klausel zu bilden.

0 Stimmen

Es führt auch zu Leistungsverbesserungen, da in der Regel weniger Sortier-/Temp-/Arbeitsspeicher verwendet wird.

0 Stimmen

Ja, ich stimme zu, dass dies der richtige Weg ist. Nicht scharf auf die zusätzliche Komplexität der (zusätzliche) verschachtelte Abfragen, aber was können wir tun.

3voto

cindi Punkte 4341

Ich stimme zu, dass die Gruppe von Liste sollte nicht implizit das gleiche wie dann nicht aggregierte Spalten auswählen. In Sas gibt es Daten Aggregation Operationen, die mehr prägnant sind.

Außerdem: Es ist schwer, ein Beispiel zu finden, bei dem es nützlich wäre, eine längere Liste von Spalten in der Gruppenliste als in der Auswahlliste zu haben. Das Beste, was mir einfällt, ist ...

create table people
(  Nam char(10)
  ,Adr char(10)
)

insert into people values ('Peter', 'Tibet')
insert into people values ('Peter', 'OZ')
insert into people values ('Peter', 'OZ')

insert into people values ('Joe', 'NY')
insert into people values ('Joe', 'Texas')
insert into people values ('Joe', 'France')

-- Give me people where there is a duplicate address record

select * from people where nam in 
(
select nam              
from People        
group by nam, adr        -- group list different from select list
having count(*) > 1
)

2voto

adopilot Punkte 4160

Wenn es Ihnen nur darum geht, Skripte einfacher zu schreiben. Hier ist ein Tipp:

In MS SQL MGMS schreiben Sie eine Abfrage in Textform, etwa wie select * from my_table Danach wählen Sie den Text mit der rechten Maustaste aus und klicken Sie auf "Abfrage im Editor entwerfen ". Sql Studio öffnet einen neuen Editor mit allen Feldern, danach wieder Rechtsklick und "Add Gruop BY" wählen Sql MGM Studio wird den Code für Sie hinzufügen.

Ich finde diese Methode äußerst nützlich für Einfügeanweisungen. Wenn ich ein Skript zum Einfügen vieler Felder in eine Tabelle schreiben muss, mache ich einfach select * from table_where_want_to_insert und ändere danach den Typ der select-Anweisung in insert,

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X