2012-03-27 5 views
4

Wie kann man eine gruppierte Ergebnismenge nur für diejenigen Gruppen filtern, die ein bestimmtes Kriterium im Vergleich zu den anderen Gruppen erfüllen? Zum Beispiel nur die Gruppen, die die maximale Anzahl der konstituierenden Datensätze haben?SQL-Gruppen miteinander vergleichen

Ich hatte gedacht, dass eine Unterabfrage wie folgt den Trick tun sollten:

in einem leeren Re-Cord-
SELECT * FROM (
    SELECT *, COUNT(*) AS Records 
    FROM  T 
    GROUP BY X 
) t HAVING Records = MAX(Records); 

jedoch die Zugabe der abschließenden HAVING Klausel Ergebnisse ... was ist los?

+1

Wenn Juho Antwort nicht gibt Ihnen, was Sie brauchen Bitte geben Sie ein, welche Art von Datenbank Sie sind Verwenden (Oracle, MySQL, SQL-Server, etc.) (mit den Tags, wo Sie in SQL einfügen. Wenn Sie nur allgemeine SQL-Lösungen möchten, erwähnen Sie dies im Hauptteil Ihrer Nachricht. Wenn Sie sich Zeit genommen haben, einige Beispieldaten und Tabellenstrukturen in Ihrem Post und auf sqlfiddle.com zu veröffentlichen, erleichtern Sie es den Benutzern, sich Ihre Frage genauer anzusehen. –

+1

@LevinMagruder: MySQL 5.1; Beispieldaten unter http://sqlfiddle.com/#!3/b4306/4 – eggyal

+0

Okay, ich benutze nicht mysql, aber jemand zeigt Ihnen eine einfachere Abfrage als die, die ich unten gezeigt habe, markieren Sie ihre Antwort als Antwort, aber wenn meine Antwort hilfreich ist und du mir eine Dankesrede schießen willst, danke. Wenn Sie so viele Probleme haben, lesen Sie vielleicht auch Fragen, die mit "Größte-pro-Gruppe" markiert sind. Es gibt viele interessante Ansätze. –

Antwort

1

Für die genaue Frage, die Sie geben, ist eine Möglichkeit, die Gruppe von Datensätzen zu sehen, wo keine andere Gruppe mehr Datensätze hat. Also, wenn Sie sagen

SELECT taxid, COUNT(*) as howMany 
GROUP by taxid 

Sie erhalten alle Landkreise und ihre Zählungen

Dann können Sie behandeln, dass Ausdrücke wie eine Tabelle durch eine Unterabfrage zu machen, und es einen Aliasnamen geben. Im Folgenden weise ich zwei "Kopien" der Abfrage den Namen X und Y zu und frage nach Taxiden, die in einer Tabelle nicht mehr vorhanden sind. Wenn es zwei mit der gleichen Nummer gibt, würde ich zwei oder mehr bekommen. Verschiedene Datenbanken haben proprietäre Syntax, insbesondere TOP und LIMIT, die diese Art der Abfrage einfacher und einfacher zu verstehen machen.

SELECT taxid FROM 
(select taxid, count(*) as HowMany from flats 
GROUP by taxid) as X 

WHERE NOT EXISTS 
(
SELECT * from 
(
    SELECT taxid, count(*) as HowMany FROM 
    flats 
    GROUP by taxid 
    ) AS Y 
    WHERE Y.howmany > X.howmany 
) 
+0

Ich bin mir bewusst, dass ich durch die Wiederholung der Unterabfrage in der 'WHERE'-Klausel die maximale Anzahl von Zeilen extrahieren kann (nur' max() 'funktioniert gut), aber es scheint ziemlich verschwenderisch, das gleiche Unterabfrage-Mehrfache aufzurufen mal; Gibt es eine Möglichkeit, auf die temporäre Tabelle zu verweisen, die sich aus der Unterabfrage in der 'FROM'-Klausel innerhalb der' WHERE'-Klausel ergibt? – eggyal

0

Versuchen Sie folgendes:

SELECT * FROM (
    SELECT *, MAX(Records) as max_records FROM (
    SELECT *, COUNT(*) AS Records 
    FROM T 
    GROUP BY X 
) t 
) WHERE Records = max_records 

Es tut mir leid, dass ich nicht die Gültigkeit dieser Abfrage jetzt testen können.

+0

Die 'SELECT MAX (Records)' in Ihrer Abfrage der zweiten Ebene schneidet das Recordset auf nur einen Datensatz ab, in dem die Felder 'Records' und 'max_records' nicht notwendigerweise identisch sind (und das Gesamtergebnis daher immer nur aus Null besteht) oder ein Datensatz); Vielleicht ist das meine ursprüngliche Abfrage und daher auch keine Ergebnisse? – eggyal

4

In MySQL (die ich nehme an, Sie verwenden, da Sie SELECT *, COUNT(*) FROM T GROUP BY X gebucht haben, die in allen RDBMS scheitern würde, die ich kenne). Sie können:

SELECT T.* 
FROM T 
     INNER JOIN 
     ( SELECT X, COUNT(*) AS Records 
      FROM T 
      GROUP BY X 
      ORDER BY Records DESC 
      LIMIT 1 
     ) T2 
      ON T2.X = T.X 

Das in MySQL getestet wurde und entfernt die implizite Gruppierung/Aggregation.

Wenn Sie Fensterfunktionen und einer der TOP/LIMIT mit Krawatten oder allgemeine Tabellenausdrücke verwenden können, wird es noch kürzer:

Windowed Funktion + CTE: (MS SQL-Server & PostgreSQL getestet)

WITH CTE AS 
( SELECT *, COUNT(*) OVER(PARTITION BY X) AS Records 
    FROM T 
) 
SELECT * 
FROM CTE 
WHERE Records = (SELECT MAX(Records) FROM CTE) 

Fensterfunktion mit TOP (MS SQL-Server getestet)

SELECT TOP 1 WITH TIES * 
FROM ( SELECT *, COUNT(*) OVER(PARTITION BY X) [Records] 
      FROM T 
     ) 
ORDER BY Records DESC 

Schließlich habe ich noch nie Orakel so apolgies für das Hinzufügen einer Lösung, die auf Orakel funktioniert ...


EDIT

Meine Lösung für MySQL nicht berücksichtigt Beziehungen nehmen, und mein Vorschlag für eine Lösung dieser Art von Schritten auf die Zehen, was Sie gesagt haben, Sie vermeiden wollen (duplicate Subqueries), so ist mir nicht sicher, ob ich nach allen helfen, aber nur für den Fall ist es hier vorzuziehen ist eine Version, die auf Ihrer Geige nach Bedarf funktioniert:

SELECT T.* 
FROM T 
     INNER JOIN 
     ( SELECT X 
      FROM T 
      GROUP BY X 
      HAVING COUNT(*) = 
        ( SELECT COUNT(*) AS Records 
         FROM T 
         GROUP BY X 
         ORDER BY Records DESC 
         LIMIT 1 
        ) 
     ) T2 
      ON T2.X = T.X 
+0

Das erste (mysql) verliert jedoch Verbindungen; was mag das sein, was eggyal will, wenn nicht, denke ich, dass du es neu schreiben musst, um es zu zählen. Die letzten beiden verlieren nicht die Bande. –

+0

@LevinMagruder Ja, habe vor ein paar Minuten bemerkt, habe eine Bearbeitung hinzugefügt, aber jetzt denke ich auch nicht, dass das OP es will, da es die Unterabfrage wiederholt, aber soweit ich das durcharbeiten kann, ist das unvermeidlich. – GarethD

+0

+1 einfacher als meine "nicht existiert" -Logik. –

Verwandte Themen