Maik W. aus E.: Ergebnismenge mit UNION erneut sortieren

Tach zusammen,

ich habe hier eine Tabelle in einer mySQl-DB der Version 5.0.32, die bei jeder Suchanfrage einen neuen Datesatz aufnimmt:

id | query | anzahl | timestamp
 1 | blabla|   12   | 2007-12-03

wobei 'anzahl' für die Anzahl der Treffer für den Suchbegriff 'query' steht.

Nun möchte ich gerne die 50 häufigsten Suchbegriffe haben und die sortiert nach den meisten Treffern. Das gelingt mit folgendem Statement:

  
(  
SELECT query, count( query ) AS wieviel, anzahl AS sort2  
FROM `tabelle`  
WHERE 1  
GROUP BY query  
ORDER BY wieviel DESC  
LIMIT 0 , 50  
)  
UNION (  
  
SELECT query, count( query ) AS wieviel, anzahl AS sort3  
FROM tabelle  
WHERE 1  
GROUP BY query  
ORDER BY anzahl  
LIMIT 0 , 50  
)  
ORDER BY sort2 DESC , wieviel DESC  
LIMIT 0 , 50  

Kann man das noch weiter optimieren oder gar viel einfacher bauen? Außerdem klappt das alphabetische Sortieren nicht, wenn ich den letzten 'Order'-Befehl ergänze:

ORDER BY sort2 DESC , wieviel DESC, query ASC

bleibt das ohne Wirkung. Wer kann helfen?

Danke und
http://www.gruss-aus-essen.de

Maik

--
Diese Dauerleihgabe wird Ihnen präsentiert von ROMY!
Maik. W. aus E. sagt Dankeschön ;-)
  1. Mit deinem UNION selektierst du beides Male die gleichen Sätze, durch das automatische DISTINCT fallen doppelte weg, so das die Ergebnismenge exakt der ersten Selektion entspricht.

      
    SELECT query, wieviel, gesamt  
    FROM (  
      SELECT query, count( query ) AS wieviel, SUM( anzahl ) AS gesamt  
      FROM `tabelle`  
      WHERE 1  
      GROUP BY query  
      ORDER BY wieviel DESC  
      LIMIT 0 , 50  
    ) t1  
    ORDER BY gesamt DESC
    

    Wählt dir erst die 50 meistgefragtesten Querys aus und sortiert dir diese nach Anzahl der Treffer.

    Warum deine Alphasortierung nicht funktioniert kann ich jetzt aus dem Stehgreif nicht sagen.

    Gruß

  2. yo,

    [code lang=sql]
    (
    SELECT query, count( query ) AS wieviel, anzahl AS sort2
    FROM tabelle
    WHERE 1
    GROUP BY query
    ORDER BY wieviel DESC
    LIMIT 0 , 50

    jedes andere dbms würde dir dabei eine fehlermeldung ausgeben und das zurecht. du gibtst spalten aus, welche weder gruppiert wurden noch aggregierst, was dann auch der grund ist, warum die sortierung nicht funktioniert. das WHERE 1 macht auch keinen sinn, ich würde es entfernen. das dein Union ebenfalls keinen sinn hat, wurde dir ja bereits gesagt und count(query) setzt man so auch nicht ein, da wäre ein count(*) angebrachter. fehlt noch der hinweis, dass bei gleichheit die LIMIT funktion nur suboptimal funktioniert, weil er eben strickt nach 50 datensätzen abschneidet, aber das kann eventuell gewollt sein.

    ich vermute mal, und es ist nur eine vermutung, du willst das hier:

    SELECT query, COUNT(*) AS wieviel, SUM(anzahl) AS sort2
    FROM tabelle
    GROUP BY query
    ORDER BY sort2 DESC, wieviel DESC
    LIMIT 0 , 50

    Ilja

    1. Tach auch Ilja,

      jedes andere dbms würde dir dabei eine fehlermeldung ausgeben und das zurecht. du gibtst spalten aus, welche weder gruppiert wurden noch aggregierst, was dann auch der grund ist, warum die sortierung nicht funktioniert. das WHERE 1 macht auch keinen sinn, ich würde es entfernen. das dein Union ebenfalls keinen sinn hat, wurde dir ja bereits gesagt und count(query) setzt man so auch nicht ein, da wäre ein count(*) angebrachter. fehlt noch der hinweis, dass bei gleichheit die LIMIT funktion nur suboptimal funktioniert, weil er eben strickt nach 50 datensätzen abschneidet, aber das kann eventuell gewollt sein.

      ich vermute mal, und es ist nur eine vermutung, du willst das hier:

      Schon nicht schlecht vermutet,

      SELECT query, COUNT(*) AS wieviel, SUM(anzahl) AS sort2
      FROM tabelle
      GROUP BY query
      ORDER BY sort2 DESC, wieviel DESC
      LIMIT 0 , 50

      gibt mir die Ergebnisse aus, die ich haben will, auch wenn jetzt die Trefferzahlen summiert sind, das ist nicht so schlimm, weil mir das Verhältnis zueinander reicht, aber die alpha-Sortierung macht mir noch Kopfzerbrechen...
      Vielleicht hier nochmal eine Willenserklärung:

      Selektiere mir genau die fünfzig häufigsten Suchanfragen und sortiere diese nach den meisten Treffern / nach dem Alphabet.

      Einfaches 'order by query' macht hier keinen Sinn, deswegen bin ich davon ausgegangen, daß die Ergebnismenge erneut sortiert werden muß...

      http://www.gruss-aus-essen.de

      Maik

      --
      Diese Dauerleihgabe wird Ihnen präsentiert von ROMY!
      Maik. W. aus E. sagt Dankeschön ;-)
      1. n'abend,

        Selektiere mir genau die fünfzig häufigsten Suchanfragen und sortiere diese nach den meisten Treffern / nach dem Alphabet.

        Wenn ich dich recht verstehe, willst du die Top 50 Datensätze nach Namen (statt Häufigkeit/Gewicht) sortiert haben. Dazu musst du in diesem Fall etwas umdenken. Es ist nicht möglich eine Menge von Datensätzen gleichzeitig nach 2 verschiedenen Kriterien zu sortieren (wobei hier kontrahierende Sortierung, nicht verfeinernde Sortierung gemeint ist!).

        Dementsprechend brauchst du eine Abfrage, um deine Top 50 Datensätze zu finden und eine weitere Abfrage, die die gefundenen Datensätze deinen Wünschen gerecht sortiert liefert.

        Ein Beispiel mit SubQuery:

          
        SELECT query, SUM(anzahl) as wieviel, COUNT(*) as anzahl  
        FROM tabelle  
        WHERE query IN (  
          SELECT query  
          FROM tabelle  
          GROUP BY query  
          ORDER BY SUM(anzahl) DESC, COUNT(*) DESC  
          LIMIT 50 /* <- wird von MySQL5 als fehler angesehen */  
        )  
        ORDER BY query ASC /* gehe mal von aus, dass du nach query sortieren willst */  
        
        

        Ein Beispiel mit SubQuery-Relation:

          
        SELECT t.*  
        FROM (  
          SELECT query, SUM(anzahl) as wieviel, COUNT(*) as anzahl  
          FROM tabelle  
          GROUP BY query  
          ORDER BY wieviel DESC, anzahl DESC  
          LIMIT 50 /* <- kann von MySQL5 als fehler angesehen werden */  
        ) AS t  
        ORDER BY t.query ASC /* gehe mal von aus, dass du nach query sortieren willst */  
        
        

        Wenn du jedoch lediglich zuerst nach Häufigkeit/Gewicht und dann nach Namen sortieren willst, bist du mit Iljas Anfrage bestens bedient. Da brauchst du in der ORDER BY Klausel nur noch das Feld _anhängen_ nach dem (der Häufigkeit/Gewicht untergeordnet) sortiert werden soll.

        weiterhin schönen abend...

        --
        Freundlich wie man war, hat man mir Großbuchstaben geschenkt.
        sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
        1. Tach auch globe,

          Selektiere mir genau die fünfzig häufigsten Suchanfragen und sortiere diese nach den meisten Treffern / nach dem Alphabet.

          Wenn ich dich recht verstehe, willst du die Top 50 Datensätze nach Namen (statt Häufigkeit/Gewicht) sortiert haben. Dazu musst du in diesem Fall etwas umdenken. Es ist nicht möglich eine Menge von Datensätzen gleichzeitig nach 2 verschiedenen Kriterien zu sortieren (wobei hier kontrahierende Sortierung, nicht verfeinernde Sortierung gemeint ist!).

          Genau so weit war ich, deswegen habe ich ja meine Versuche mit Union gemacht...

          Dementsprechend brauchst du eine Abfrage, um deine Top 50 Datensätze zu finden und eine weitere Abfrage, die die gefundenen Datensätze deinen Wünschen gerecht sortiert liefert.

          Exakt!

          Ein Beispiel mit SubQuery:

          SELECT query, SUM(anzahl) as wieviel, COUNT() as anzahl
          FROM tabelle
          WHERE query IN (
            SELECT query
            FROM tabelle
            GROUP BY query
            ORDER BY SUM(anzahl) DESC, COUNT(
          ) DESC
            LIMIT 50 /* <- wird von MySQL5 als fehler angesehen /
          )
          ORDER BY query ASC /
          gehe mal von aus, dass du nach query sortieren willst */

          Nur für's Protokoll/ Archiv:  
            
          Wenn das Statement von Fehlern bereinigt ist  
            
          ~~~sql
            
          SELECT query, SUM(anzahl) as wieviel, COUNT(*) as anzahl  
          FROM tabelle  
          WHERE query IN (  
            SELECT query  
            FROM tabelle  
            GROUP BY query  
            ORDER BY SUM(anzahl) DESC, COUNT(*) DESC  
          )  
          GROUP BY query  
          ORDER BY query ASC  
          LIMIT 50  
          
          

          läuft die Anfrage in ein Timeout, auf dem lokalen Testserver ohne Beschränkung rechnet es 112 Sekunden... nicht so performant.

          Ein Beispiel mit SubQuery-Relation:

          SELECT t.*
          FROM (
            SELECT query, SUM(anzahl) as wieviel, COUNT() as anzahl
            FROM tabelle
            GROUP BY query
            ORDER BY wieviel DESC, anzahl DESC
            LIMIT 50 /
          <- kann von MySQL5 als fehler angesehen werden /
          ) AS t
          ORDER BY t.query ASC /
          gehe mal von aus, dass du nach query sortieren willst */

          Genau das ist es!  
            
          
          > Wenn du jedoch lediglich zuerst nach Häufigkeit/Gewicht und dann nach Namen sortieren willst, bist du mit Iljas Anfrage bestens bedient. Da brauchst du in der ORDER BY Klausel nur noch das Feld \_anhängen\_ nach dem (der Häufigkeit/Gewicht untergeordnet) sortiert werden soll.  
          
          Das macht nicht viel Sinn, weil die alphabetische Sortierung nur dann greift, wenn die Häufigkeit exakt gleich ist (was bei meinen Daten \_gar\_ nicht vorkommt).  
            
          Besten Dank und Gruß an den großen See...  
            
            
          <http://www.gruss-aus-essen.de>  
            
          Maik
          
          -- 
          ![Diese Dauerleihgabe wird Ihnen präsentiert von ROMY!](http://www.gruss-aus-essen.de/selfforum/totes_huhn.jpg)  
          Maik. W. aus E. sagt Dankeschön ;-)  
          
          
          1. n'abend,

            Genau so weit war ich, deswegen habe ich ja meine Versuche mit Union gemacht...

            Mittels UNION schweißt du die Ergebnismengen zweier Abfragen zu einer Ergebnismenge zusammen.

            SELECT query, SUM(anzahl) as wieviel, COUNT() as anzahl
            FROM tabelle
            WHERE query IN (
              SELECT query
              FROM tabelle
              GROUP BY query
              ORDER BY SUM(anzahl) DESC, COUNT(
            ) DESC
            )
            GROUP BY query
            ORDER BY query ASC
            LIMIT 50

            
            > läuft die Anfrage in ein Timeout, auf dem lokalen Testserver ohne Beschränkung rechnet es 112 Sekunden... nicht so performant.  
              
            Was daran liegt, dass das eine ziemlich dämliche Abfrage ist und der Query-Optimizer da wohl nicht das macht, was man sich wünscht. (Nämlich erkennen, dass er die Aggregatfunktionen der äußeren Query nicht erneut durchlaufen muss, sondern die Ergebnisse der inneren Query nehmen kann...)  
              
            Wenn wir betrachten, was hier passiert, wird uns auch klar, warum das so verdammt lange dauert:  
            [innere Query]  
            (1-1) Alle Datensätze werden nach dem Feld query gruppiert  
            (1-2) Die Summen des anzahl-Feldes pro Gruppe wird berechnet  
            (1-3) Die Anzahl Datensätze pro Gruppe wird berechnet  
            (1-4) Die Ergebnismenge wird zuerst nach der Anzahl (1-3), dann nach der Summe (1-2) sortiert  
            [äußere Query]  
            (2-5) Die Datensätze werden gesucht, deren query-Feld einem der Werte der SubQuery entspricht  
            (2-6) Die gefundenen Datensätze werden nach dem Feld query gruppiert  
            (2-7) Die Summen des anzahl-Feldes pro Gruppe wird berechnet  
            (2-8) Die Anzahl Datensätze pro Gruppe wird berechnet  
            (2-9) Die Ergebnismenge wird zuerst nach dem Feld query Sortiert  
              
            Wir machen an dieser Stelle also jede Berechnung doppelt.  
              
            
            > > ~~~sql
              
            
            > > SELECT t.*  
            > > FROM (  
            > >   SELECT query, SUM(anzahl) as wieviel, COUNT(*) as anzahl  
            > >   FROM tabelle  
            > >   GROUP BY query  
            > >   ORDER BY wieviel DESC, anzahl DESC  
            > >   LIMIT 50 /* <- kann von MySQL5 als fehler angesehen werden */  
            > > ) AS t  
            > > ORDER BY t.query ASC /* gehe mal von aus, dass du nach query sortieren willst */  
            > > 
            
            

            Genau das ist es!

            Hier machen wir die obigen Schritte (1-1) bis (1-4) durch. Danach berechnen wir aber keine weiteren Dinge, sondern sortieren die Ergebnismenge lediglich neu.

            Hat die LIMIT Klausel denn zu Problemen geführt? Welches DBMS setzt du überhaupt ein?

            Besten Dank und Gruß an den großen See...

            Blubberige Grüße zurück nach E-Punkt :)

            weiterhin schönen abend...

            --
            Freundlich wie man war, hat man mir Großbuchstaben geschenkt.
            sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
            1. Tach auch globe,

              Mittels UNION schweißt du die Ergebnismengen zweier Abfragen zu einer Ergebnismenge zusammen.

              Ja,ja, ich weiß...

              SELECT t.*
              FROM (
                SELECT query, SUM(anzahl) as wieviel, COUNT() as anzahl
                FROM tabelle
                GROUP BY query
                ORDER BY wieviel DESC, anzahl DESC
                LIMIT 50 /
              <- kann von MySQL5 als fehler angesehen werden /
              ) AS t
              ORDER BY t.query ASC /
              gehe mal von aus, dass du nach query sortieren willst */

              
              > > Genau das ist es!  
              >   
              > Hat die LIMIT Klausel denn zu Problemen geführt?  
              
              Nein, im Subquery-Relation-Beispiel nicht, im zähen, oberen Subquery-Beispiel schon, da stieg er mit der netten Meldung "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery" aus.  
                
              Welches DBMS setzt du überhaupt ein?  
              ...[mySQl-DB der Version 5.0.32](https://forum.selfhtml.org/?t=162957&m=1060780)...  
                
              <http://www.gruss-aus-essen.de>  
                
              Maik
              
              -- 
              ![Diese Dauerleihgabe wird Ihnen präsentiert von ROMY!](http://www.gruss-aus-essen.de/selfforum/totes_huhn.jpg)  
              Maik. W. aus E. sagt Dankeschön ;-)  
              
              
              1. n'abend,

                Hat die LIMIT Klausel denn zu Problemen geführt?
                Nein, im Subquery-Relation-Beispiel nicht, im zähen, oberen Subquery-Beispiel schon, da stieg er mit der netten Meldung "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery" aus.

                Ja, die Meldung kommt mir bekannt vor, deswegen wies ich drauf hin. Fein, dass das beim Relation-SubQuery (ob das auch einen richtigen Namen hat?) funktioniert. Wenigstens das bekommt MySQL gebacken...

                weiterhin schönen abend...

                --
                #selfhtml hat ein Forum?
                sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|