André Mantz: Komplizierte Abfrage?!?

Hallo,

ich habe ein kleines Problem mit einer MySQL-Tabelle.

In der Tabelle stehen Nachrichten (interne Mails von Usern innerhalb der Anwendung). Die Tabelle sieht vereinfacht so aus:

+---------+---------+----------+
| von     | an      | Mailtext |
+---------+---------+----------+
| Müller  | Maier   | ...      |
| Maier   | Schmitz | ...      |
| Schmitz | Maier   | ...      |
| Bauer   | Müller  | ...      |
| ...     | ...     | ...      |

Ich brauche nun eine Abfrage, die für jeden Benutzer die Summe seiner gesendeten und empfangenen Nachrichten ermittelt.

Das gewünschte Ergebnis sollte also so aussehen:

+----------+--------+
| Benutzer | Anzahl |
+----------+--------+
| Bauer    |   1    |
| Maier    |   3    |
| Müller   |   2    |
| Schmitz  |   2    |
| ...      |  ...   |

Ich habe es bisher nicht hinbekommen. Mein bisher bester Ansatz sieht so aus:

SELECT von AS benutzer, count(*) as anzahl
     FROM tabelle
          GROUP BY von
UNION ALL
SELECT an  AS benutzer, count(*) as anzahl
     FROM tabelle
          GROUP BY an
ORDER BY benutzer

allerdings erhalte ich dann immer zwei Datensätze pro Benutzer, einen mit der Anzahl seiner gesendeten und einen mit der Anzahl seiner empfangenen Nachrichten. Ich kriege kein GROUP BY auf das Gesamtergebnis hin. Geht das überhaupt, oder bin ich mit meinem Lösungsansatz insgesamt auf dem Holzweg?

Danke für eure Hilfe.

Gruß, André

  1. Morgen André,

    versuchs mal kurz und schmerzlos mit:
    SELECT von, count (von) FROM tabelle group by 1,2 order by 1
    Müßte eigentlich so passen.

    Hope it helps
    Grüße Hansjörg

    1. versuchs mal kurz und schmerzlos mit:
      SELECT von, count (von) FROM tabelle group by 1,2 order by 1
      Müßte eigentlich so passen.

      Hallo Hansjörg,

      mal ganz abgesehen davon, dass das nicht geht (Fehler: Can't group on 'count(von)'), verstehe ich deinen Ansatz nicht? wie sollte diese Abfrage die Summe der gesendeten und empfangenen Nachrichten aller User ermitteln?

      Gruß, André

      1. Servus,
        Sorry erstmal, hab übersehen, dass du auch die Empfänger mit in der Liste haben möchtest.

        mal ganz abgesehen davon, dass das nicht geht (Fehler: Can't group on 'count(von)'),

        tja mit HypersonicSQL wirft mir genau dieses Statement die Sender mit entsprechender Anzahl aus. Hab gerade leider keine MySQL-DB zur Hand. Ich such weiter nach ner Lösung für dein Problem. Kann sich nur um Stunden handeln

        Gruß Hansjörg

        1. Servus André

          also hier jetzt noch ein Versuch:

          select a, SUM(b) from (
          SELECT von as a, count(von) as b FROM tabelle group by von
           union all
          SELECT an as a, count(an) as b FROM tabelle group by an
          ) group by a

          Mit einer Oracle-DB funktioniert die Abfrage. Deine MySQL-DB wird womöglich mit dem Subselect nicht richtig umgehen können, aber ein Versuch ists wert. Wenn das nicht weiterhilft, dann bin ich mit meinem Latein so ziemlich am Ende.
          Hope it helps
          Gruß Hansjörg

  2. yo,

    mal davon abgesehen, dass mitarbeiter auch den gleichen namen haben können, was in deinen tabellen zu einem problem führt und das eventuell eine mail an mehrere gesendet werden könnte, würde ich zwei abfragen machen und beide ergebnisse in der anwendnung addieren.

    mit join uns unterabfragen ist es auch als ein ergebnis möglich, aber das ist nicht sehr performant und erzeugt eine komplizierte abfrage. im zweifelsfalle immer kis

    Ilja

    1. Hallo Ilja,

      mal davon abgesehen, dass mitarbeiter auch den gleichen namen haben können, was in deinen tabellen zu einem problem führt und das eventuell eine mail an mehrere gesendet werden könnte, ...

      Ich hatte ja extra geschrieben "vereinfacht dargestellt". Natürlich wird in der tatsächlich vorhandenen Tabelle nicht mit Namen sondern mit internen Usernummern gearbeitet ... wobei das aber für meine Problemstellung nebensächlich ist.

      würde ich zwei abfragen machen und beide ergebnisse in der anwendnung addieren.
      mit join uns unterabfragen ist es auch als ein ergebnis möglich, aber das ist nicht sehr performant und erzeugt eine komplizierte abfrage. im zweifelsfalle immer kis

      Meiner Erfahrung nach erledigt MySQL das deutlich schneller als PHP. Denn wenn ich zwei Abfragen mache bei z.B. 20.000 Maileinträgen in der DB, dann müsste ich ja danach 20.000 mal eine Schleife durchlaufen um in PHP (oder auch Perl) die Ergebnisse zusammenzuführen.
      Wenn du eine Lösung mittels join und unterabfragen kennst... her damit. Genau danach suche ich.

      Gruß, André

      1. yo,

        Ich hatte ja extra geschrieben "vereinfacht dargestellt". Natürlich wird in der tatsächlich vorhandenen Tabelle nicht mit Namen sondern mit internen Usernummern gearbeitet ... wobei das aber für meine Problemstellung nebensächlich ist.

        ahh ok, das ist gut so. bleibt noch das problem, dass man eine mail nur an einen schicken kann und nicht an mehrere, aber egal.

        Meiner Erfahrung nach erledigt MySQL das deutlich schneller als PHP. Denn wenn ich zwei Abfragen mache bei z.B. 20.000 Maileinträgen in der DB, dann müsste ich ja danach 20.000 mal eine Schleife durchlaufen um in PHP (oder auch Perl) die Ergebnisse zusammenzuführen.

        datenbank sind dafür auch optimert.d as porblem ist aber, dass unterabfragen selbst für dbms sehr unperformant sind, weil die unterabfragen jedesmal neu ausgeführt werden, für jeden datensatz der eigentlichen abfrage. ich würde vielleicht beides mal versuchen, zwei abfragen stelen und sie auf anwenderprogramm ebene addieren und eine unterabfrage, um zu sehen, was schneller geht. ein anderes problem ist noch, dass nicht jedes dbms unterabfragen ünterstützt, bzw. nicht in jeder version.

        aber lös einfach dein union auf und mache eine unterabfrage draus. wie genau die syntax aussieht, kann ich out of the head nicht sagen, probieren und nachschauen. aber vom sinn her in etwa so.

        SELECT von AS benutzer, count(*) +
               (SELECT count(*)FROM tabelle GROUP BY an) AS anzahl
             FROM tabelle
                  GROUP BY von

        vielleicht fällt mir auch der join ein, mal sehen.

        Ilja

        Ilja

        1. Nochmal Hallo,

          SELECT von AS benutzer, count(*) +
                 (SELECT count(*)FROM tabelle GROUP BY an) AS anzahl
               FROM tabelle
                    GROUP BY von

          Also so ein Kontrukt ist mir bisher noch nicht begegnet. Finde auch keine Entsprchung im MySQL-Tutorial dazu.
          Try an error ergibt leider einen Fehler (1064: Error in SQL Syntax)

          Gruß, André

          1. yo,

            Also so ein Kontrukt ist mir bisher noch nicht begegnet. Finde auch keine Entsprchung im MySQL-Tutorial dazu.
            Try an error ergibt leider einen Fehler (1064: Error in SQL Syntax)

            geht auch nicht, das war murx, was ich da oben gebastelt habe. da in der unterabfrage mehr als ein wert zurückgeliefert wird. muss mal ein wenig mehr drüber nachdenken.

            Ilja

          2. Hi André

            Also so ein Kontrukt ist mir bisher noch nicht begegnet. Finde auch keine Entsprchung im MySQL-Tutorial dazu.
            Try an error ergibt leider einen Fehler (1064: Error in SQL Syntax)

            Müsste ja in der Klammer auch heissen:
            Select count(*) from tabelle as b where benutzer.erstername = b.zweitername.

            Afaik beherrscht MySQL sowas aber sowieso nicht. Ich würd mir überlegen, das Datenbankdesign zu überarbeiten in der Form:

            Name | Sender/Empfänger | Nachricht

            Wobei Sender/Empfänger ein Flag darstellt das die Richtung der Nachricht angibt.

            Gruss Daniela

          3. yo,

            ok bevor wir es noch komplizierter machen, gibt es einen anderen weg. du kannst deine union abfrage nehmen und es als tabelle in einer weiteren abfrage mit einer gruppierung einfügen. dass sollte dann zu dem erwünschten ergebnis führen, ein datensatz pro benutzer.

            SELECT von AS benutzer, count (*) AS Anzahl FROM
               (
               SELECT von AS benutzer, count(*) as anzahl
                 FROM tabelle
                      GROUP BY von
               UNION ALL
               SELECT an  AS benutzer, count(*) as anzahl
                 FROM tabelle
                      GROUP BY an
               )
            GROUP BY benutzer
            ORDER BY benutzer

            versuch mal das konstrukt. ich rate aber mehr als ich es hier jetzt ausprobieren kann.

            Ilja

  3. yo,

    bin zuhause angekommen und habe noch einmal über das problem nachgedacht. das davor von mir war irgendwie gewollt und nicht gekonnt.

    der knackpunckt liegt meiner meinung nach in der gruppierung (klar), aber vor allem daran, dass eine tabelle fehlt und zwar die tabelle, wo die anwender drinne stehen. es kann ja zum beispiel auch sein, dass du in die einträge auch die personen haben willst, die noch gar keine mails geschrieben/empfangen haben und ihnen den wert 0 zuordnen. diese wären ja nicht in der tabelle enthalten. man kann diese aber auch rauslassen. wichtig ist nur, dass die anwender tabelle mit ins spiel kommt und dann läßt sich meiner meinung nach auch ein join bilden, weil wir das dann nicht mehr über die gruppierung machen müssen, sondern eben die anwendertabelle hinzuziehen können, wenn es darum geht, für ein bestimmte person die anzahl zu ermitteln.

    die gruppierung muss raus, weil man eine gruppierung über zwei spalten nicht mit einer ODER, sondern nur mit einer UND logik erzeugen kann. und wenn die raus geht, dann brauchen wir einen anderen bezug, auf wlechen anwender wir uns gerade beziehen, wenn wir die tabelle abfragen. ich hoffe du bist noch hier und das ist soweit verständlich.

    Ilja