Summe und JOIN
hawkmaster1
- mysql
0 Der Martin0 hawkmaster10 dedlfix0 Der Martin0 hawkmaster10 dedlfix
0 dedlfix1 Rolf b
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
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
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
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.
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
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
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.
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.
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