hawkmaster1: Summe und JOIN

Hallo zusammen,

irgendwie stehe ich gerade auf dem Schlauch :-)

Ich habe zwei Tabellen. Tabelle A Sales. Hier gibt es 3 Zeilen mit einer Stundenanzahl (20,40,20) also insgesamt 80 Stunden. Tabelle B Support hat eine Spalte supporthours, Hier gibt es 9 Einträge mit insgesamt 71,5 Stunden Ich möchte als ergenis also eine Reihe in der steht:

soldmandays, SupportStunden 80, 71,5

Die Abfrage macht jedoch 720 Std und 214,5, also multipliziert 3 Zeile aus Tabelle A mit 9 Zeilen aus Tabelle B.

SELECT
	SUM(replace(A.soldmandays, ',', '.')) AS soldmandays,
        SUM(replace(B.supporthours, ',', '.')) AS SupportStunden
	
	FROM 
		sales A
	JOIN 
		support B ON B.aufnumber = A.aufnumber
	WHERE 
		A.solution = 34
	AND A.aufnumber = 'Test123'
    
    GROUP BY B.aufnumber,A.aufnumber

Hat jemand eine Idee?

vielen Dank

viele Grüße hawk

  1. Hi,

    irgendwie stehe ich gerade auf dem Schlauch :-)

    dann mach mal einen Schritt zur Seite. ;-)

    Hat jemand eine Idee?

    Ich bin datenbanktechnisch nicht so bewandert, dass ich dir da konkret helfen könnte. Aber eine Sache fällt mir auf, auch wenn sie nicht konkret mit dem Problem zu tun hat:

    SELECT
            SUM(replace(A.soldmandays, ',', '.')) AS soldmandays,
            SUM(replace(B.supporthours, ',', '.')) AS SupportStunden
            ...
    

    Das sieht nach einem gravierenden Designfehler aus: Du speicherst Zahlenwerte als Strings, und dann auch noch mit einem Komma als Dezimaltrennzeichen, so dass du sie umständlich wieder rückwandeln musst, um etwas damit anfangen zu können?

    Warum? Warum legst du die Spalten nicht einfach als Typ FLOAT an?

    So long,
     Martin

    --
    Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
    - Douglas Adams, The Hitchhiker's Guide To The Galaxy
    1. Hi,

      Das sieht nach einem gravierenden Designfehler aus: Du speicherst Zahlenwerte als Strings, und dann auch noch mit einem Komma als Dezimaltrennzeichen, so dass du sie umständlich wieder rückwandeln musst, um etwas damit anfangen zu können?

      Warum? Warum legst du die Spalten nicht einfach als Typ FLOAT an?

      Ja das hätte man sicher anders / besser machen können. Ursprünglich wollte man die Eingabe für den Anwender der Zeiten halt mit Komma erlauben. Das hat jetzt aber erst mal nichts mit meinem Problem zu tun vermute ich mal. Danke für den Hinweis.

      Gruss

      1. Tach!

        Ja das hätte man sicher anders / besser machen können. Ursprünglich wollte man die Eingabe für den Anwender der Zeiten halt mit Komma erlauben.

        Das ist aber kein Grund, ungünstige Daten in der Datenbank abzulegen. Man kann ja auch die Eingabedaten erstmal normalisieren - sprich: in die interne Form bringen.

        dedlfix.

      2. Hallo,

        Warum legst du die Spalten nicht einfach als Typ FLOAT an?

        Ja das hätte man sicher anders / besser machen können. Ursprünglich wollte man die Eingabe für den Anwender der Zeiten halt mit Komma erlauben.

        dagegen spricht ja auch nichts. Aber die Art der Darstellung (Eingabe ebenso wie Ausgabe) sollte sich nicht in der Datenhaltung niederschlagen. Man würde ja auch keine Strings aus Großbuchstaben speichern, um Zahlen in römischen Ziffern ein- oder auszugeben, sondern man würde diese Umwandlung im Frontend durchführen, die Werte aber ansonsten in der Verarbeitungskette als reine Zahlenwerte führen.

        Übrigens ist die Eingabe von Zeiten mit gebrochenen Werten sowieso problematisch, weil viele Menschen sich durch die sexagesimale Teilung aufs Glatteis führen lassen. Sie neigen dann dazu, beispielsweise 1.45 oder 1,45 für "eine Stunde und 45 Minuten" einzutragen.

        Das hat jetzt aber erst mal nichts mit meinem Problem zu tun vermute ich mal.

        Das sagte ich ja schon.

        Ciao,
         Martin

        --
        Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
        - Douglas Adams, The Hitchhiker's Guide To The Galaxy
        1. Hallo danke nochmals, du meinst also man hätte im User Interface für den Anwender es ruhig bei der Einabe mit Komma also eta 4,5 belassen können, aber dann halt vor dem Speichern mit PHP es in einen Float umwandeln?

          Gruss hawk

          1. Tach!

            du meinst also man hätte im User Interface für den Anwender es ruhig bei der Einabe mit Komma also eta 4,5 belassen können, aber dann halt vor dem Speichern mit PHP es in einen Float umwandeln?

            Ja, aber eigentlich schon eher. Nicht erst beim Speichern, sondern gleich bei der Bearbeitung der Eingabedaten (fachliche und syntaktische Plausibilitätskontrolle). Man will in der Regel im gesamten Programmverlauf abzüglich Ein- und Ausgabe mit den eigentlichen Daten und nicht mit einer bestimmten Darstellungsform von ihnen arbeiten.

            dedlfix.

  2. Tach!

    Ich habe zwei Tabellen. Tabelle A Sales. Hier gibt es 3 Zeilen mit einer Stundenanzahl (20,40,20) also insgesamt 80 Stunden. Tabelle B Support hat eine Spalte supporthours, Hier gibt es 9 Einträge mit insgesamt 71,5 Stunden Ich möchte als ergenis also eine Reihe in der steht:

    soldmandays, SupportStunden 80, 71,5

    Die Abfrage macht jedoch 720 Std und 214,5, also multipliziert 3 Zeile aus Tabelle A mit 9 Zeilen aus Tabelle B.

    Das SUM() bezieht sich nicht auf die Daten in der Tabelle, sondern auf die Zwischenergebnismenge, die nach dem FROM, JOIN und WHERE entstanden ist. Und das ist in deinem Fall ein kartesisches Produkt. Nimm mal die beide SUM() raus und füg stattdessen ein * ein, dann siehst du die Menge, die zu dem beobachteten Ergebenis führt. Der Join ist also nicht zielführend, jedenfalls nicht in der Form.

    Hat jemand eine Idee?

    Ohne jetzt konkret zu probieren, ob das zielführend ist, aber als erster Gedanke kommt mir, einzelne Querys zu nehmen. Wenns unbedingt ein kombiniertes Ergebenis sein soll, dann die beiden als Subquery in einem SELECT ohne FROM notieren.

    dedlfix.

  3. Ich sag jetzt nix neues, mache aber ein paar Beispiele :)

    Da Du zwischen Sales und Support keine 1:1 Beziehung hast, muss mindestens eine der beiden Summen falsch sein. Ein JOIN paart "passende" Zeilen aus zwei Tabellen und das Ergebnis sind kombinierte Zeilen mit den Daten aus beiden passenden Zeilen. In deinem Fall passen auf jede Sales Zeile sieben Support-Zeilen, d.h. du bekommst 21 Ergebniszeilen, in denen sich jeder Sale sieben Mal wiederholt und jeder Support dreimal.

    Aber selbst in dem Fall, dass Du eine 1:n Beziehung zwischen Sales und Support hättest (also zu jedem Supportsatz immer genau einen Sales-Satz), hast Du bei drei Supports zu einem Sale diesen Sale dann dreimal im Ergebnis. Und deswegen auch dreimal in der Summe.

    JOIN ist hier also definitiv nicht dein Freund.

    Du hast drei Möglichkeiten. Die REPLACEs lass ich in meinem Beispielen mal weg...

    (1) zwei getrennte Queries, die Tage und Stunden einzeln summieren. Nachteil: Du fliegst zwei Runden über den SQL Server.

    (2) ein UNION. Dabei musst Du nur achtgeben, dass Du nicht Tage und Stunden addierst.

    SELECT X.Art, SUM(X.Wert) as Wert
    FROM (
       SELECT 'MD' as Art, A.SoldManDays as Wert FROM Sales WHERE AufNumber = 'Test123'
      UNION
       SELECT 'SH' as Art, A.SupportHours as Wert FROM Support WHERE AufNumber = 'Test123'
    ) X
    GROUP BY X.Art
    

    Ob du den X Namen brauchst, weiß ich nicht, das hängt ggf. vom SQL Server ab. Auf diese Weise bekommst Du zwei Sätze, einen mit Manntagen und einen mit Supportstunden.

    (3) Ein SELECT SELECT. Der liefert Dir eine Ergebniszeile mit zwei Spalten, also eigentlich das, was Du willst.

    SELECT (SELECT SUM(SoldManDays) FROM SALES s WHERE s.AufNumber = 'Test123') AS SoldManDays,
           (SELECT SUM(SoldManDays) FROM SUPPORT p WHERE p.AufNumber = 'Test123') AS SupportHours
    

    Was Du davon wählst, dürfte Geschmackssache sein. Nr. 1 ist auf jeden Fall am langsamsten (weil zwei Server-Roundtrips), kann aber bei großen Datenmengen besser für die Last am SQL Server sein weil die einzelnen Queries weniger aufwändig sind. Ob es zwischen 2 und 3 Unterschiede in der Last am SQL Server gibt, weiß ich nicht.

    Gruß Rolf