mixmastertobsi: MySQL fehlerhafte Summe

Hallo Zusammen,

ich möchte alle Aufträge eine Woche summieren, doch leider kommt hier das falsche Ergebnis raus, sobald noch ein paar JOINs als Abfrage-Parameter hinzufüge.

Mit SUM(distinct gesamtpreis) klappt es leider auch nicht… Aufgrund der Tatsache, dass es für einen Auftrag in der Tabelle "auftrag_ship" mehrere Einträge geben kann, wird der Datensatz doppelt summiert...aber warum?

Die Abfrage sieht in etwa so aus.

SELECT SUM(auftrag.gesamtpreis) as g1, COUNT(auftrag_rechnung.auftragnr) as value 
FROM auftrag_rechnung
JOIN auftrag_info ON auftrag_info.auftragnr=auftrag_rechnung.auftragnr AND auftrag_info.status='1' AND auftrag_info.date>'2019-01-07'
JOIN auftrag_ship ON auftrag_ship.auftragnr=auftrag_rechnung.auftragnr
JOIN auftrag ON auftrag.auftragnr=auftrag_rechnung.auftragnr
  1. Tach!

    ich möchte alle Aufträge eine Woche summieren, doch leider kommt hier das falsche Ergebnis raus, sobald noch ein paar JOINs als Abfrage-Parameter hinzufüge.

    Das Problem ist dann das Ermitteln der richtigen Ergebnismenge - oder das richtige Ermitteln der Ergebnismenge.

    Aufgrund der Tatsache, dass es für einen Auftrag in der Tabelle "auftrag_ship" mehrere Einträge geben kann, wird der Datensatz doppelt summiert...aber warum?

    Am besten mal die Query mit SELECT * statt SUM() und COUNT() ausführen, damit du siehst, welche Daten in der Ergebnismenge sind, auf dass du sie weiter einschränken kannst, auf das was du wirklich abfragen möchtest. Es kann helfen, Joins durch Correlated Subquerys auszutauschen, besonders wenn von der gejointen Tabelle lediglich ein einzelner Wert pro Datensatz der Hauptquery erwartet wird.

    Die Abfrage sieht in etwa so aus.

    Nützt mir nicht viel ohne zu wissen, warum der Join erfolgt und wie die Tabellen sowie Daten aussehen.

    dedlfix.

  2. Hallo mixmastertobsi,

    dann JOINe auftrag_ship doch einfach nicht. Es wird ja nichts daraus verwendet.

    Wenn Du das lediglich für's Forum weggelassen hast, dann müsste man gucken was Du daraus verwendest, um raten zu können, ob ein Subselect zielführend ist.

    Und Du müsstest deine Kardinalitäten genau benennen. Du zeigst 4 Tabellen: auftrag, auftrag_info, auftrag_rechnung und auftrag_ship; da müsstest Du klarstellen wie die Verhältnisse in den Relationen von auftrag zu den 3 anderen sind. 1:1 oder 1:n.

    Wenn es 1:1 ist, könnte man auch fragen, warum es mehrere Tabellen sind. Wenn es 1:n ist, dürfte es außer bei auftrag_ship ggf. noch weitere Probleme geben können.

    Rolf

    --
    sumpsi - posui - clusi
  3. Schritt 1 ist immer: ordentlich notieren!

    Denn das hilft ungemein dabei, zu erkennen, was man eigentlich notiert hat. In Deinem Fall:

    SELECT
        SUM( auftrag.gesamtpreis ) as g1,
        COUNT( auftrag_rechnung.auftragnr ) as value 
    FROM
        auftrag_rechnung
    JOIN 
        auftrag_info ON auftrag_info.auftragnr = auftrag_rechnung.auftragnr 
        AND auftrag_info.status = '1'
        AND auftrag_info.date > '2019-01-07'
    JOIN
        auftrag_ship ON auftrag_ship.auftragnr = auftrag_rechnung.auftragnr
    JOIN
        auftrag ON auftrag.auftragnr = auftrag_rechnung.auftragnr
    

    klappt es leider auch nicht… Aufgrund der Tatsache, dass es für einen Auftrag in der Tabelle "auftrag_ship" mehrere Einträge geben kann, wird der Datensatz doppelt summiert...aber warum?

    Womöglich wegen der Art des Joins. Versuchs mal mit einem "Cross Join mit einer Beschränkung der Ergebnisse".

    SELECT
        SUM( `auftrag`.`gesamtpreis` ) as g1,
        COUNT( `auftrag_rechnung`.`auftragnr` ) as value 
    FROM
        `auftrag_rechnung`,
        `auftrag_info`,
        `auftrag_ship`,
        `auftrag`
    WHERE
            `auftrag_info`.`auftragnr` = `auftrag_rechnung`.`auftragnr`
        AND `auftrag_ship`.`auftragnr` = `auftrag_rechnung`.`auftragnr`
        AND `auftrag`.`auftragnr`      = `auftrag_rechnung`.`auftragnr`
        AND `auftrag_info`.`status`    = '1'
        AND `auftrag_info`.`date`      > '2019-01-07'
    ;
    
    1. Also, das JOIN für auftrag_ship habe ich verwendet, weil MySQL NUR die Datensätze von auftrag.gesamtpreis summieren soll, welche auch einen auftrag_ship Datensatz haben.

      Problem ist, dass wenn es zwei mal einen auftrag_ship Datensatz gibt, auch zwei Reihen ausgegeben werden, obwohl es auftrag_rechnung nur einmal gibt.

      Ich schreibe es Euch mal vereinfacht auf…

      DB-Auftrag

      auftragnr | Gesamtpreis
      ------------------
      1 | 1000
      2 | 500
      3 | 200
      

      DB-Auftrag_Rechnung

      id | auftragnr
      ------------------
      1 | 1
      2 | 3
      

      DB-Auftrag_info

      id | auftragnr | status | value
      ------------------------------
      1 | 1 | 1 | 1
      1 | 3 | 1 | 1
      

      DB-Auftrag_ship

      ID | auftragnr | date | ship
      -------------------------
      1 | 1 | 2019-01-12 | 3
      1 | 1 | 2019-01-12 | 5
      1 | 1 | 2019-01-12 | 3
      1 | 3 | 2019-01-12 | 3
      
      1. Hi,

        Also, das JOIN für auftrag_ship habe ich verwendet, weil MySQL NUR die Datensätze von auftrag.gesamtpreis summieren soll, welche auch einen auftrag_ship Datensatz haben.

        Dann joine das nicht, sondern frage im WHERE ab, ob ein passender Datensatz in auftrag_ship existiert.

        cu,
        Andreas a/k/a MudGuard

    2. Hallo ursus,

      seit wann macht es einen Unterschied, ob ich die JOIN-Bedingung mit ON oder im WHERE notiere?

      (Mal abgesehen von dem Umstand, dass es gaaanz früher ON noch nicht gab)

      Aber wo Du das so schön säuberlich notiert hast, sehe ich was anderes (nicht dass es Auswirkungen auf die Funktion der Query hätte, es stört nur meinen Ordnungssinn): Wenn ich eine Query formuliere, sollten die Join-Bedingungen analog zu den Relationen im Modell notiert werden. Ich nehme an, dass die auftrag-Tabelle die zentrale Tabelle ist und die anderen davon abhängig sind. Dementsprechend sollte immer gegen auftrag.auftragnr geJOINt werden.

      Rolf

      --
      sumpsi - posui - clusi
    3. Tach!

      Womöglich wegen der Art des Joins. Versuchs mal mit einem "Cross Join mit einer Beschränkung der Ergebnisse".

      Inner Join und Cross Join sind unter MySQL gleichwertige Äquivalente zum impliziten Join, den du eigentlich meinst, also Tabellen kommasepariert und über die WHERE-Klausel verknüpft. Das erzeugt immer dasselbe kartesische Produkt.

      dedlfix.