sum() liefert falsche werte

  • Hallo zusammen,

    ich bin noch frisch in Datenbanken und bin mich noch am Einlesen. Ich habe mir testweise eine Datenbank erstellt, mit welcher ich Ausgaben, Summen, usw. am Testen bin. Soweit blicke ich auch durch, allerdings gibt es eine Sache, die partout nicht funktionieren will: SUM()

    Ich stelle euch hier kurz den Code ein, damit ihr den Query prüfen könnt. Vielleicht bin ich auch zu dumm :D

    Spoiler anzeigen
    [autoit]


    $sMon = "Mai"
    $hDB = _SQLite_Open("Monatskosten.sqlite")

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Hier hab ich schon Integer, Numeric und Decimal probiert bei Preis hinten..
    _SQLite_Exec(-1, "CREATE TABLE MonDB (ID INTEGER PRIMARY KEY,Monat Text,Jahr Text,Grund Text,Kategorie Text,Preis Numeric);")
    ;~ ich habe es sowohl mit Komma als auch mit Punkt probiert. (48,34 und 48.34)
    _SQLite_Exec(-1, "INSERT INTO MonDB(Monat, Jahr, Grund, Kategorie, Preis) VALUES ('Februar', '2015', 'Tanken', 'Auto', '48,34');")
    _SQLite_Exec(-1, "INSERT INTO MonDB(Monat, Jahr, Grund, Kategorie, Preis) VALUES ('September', '2015', 'Reinigung', 'Auto', '78,50');")
    _SQLite_Exec(-1, "INSERT INTO MonDB(Monat, Jahr, Grund, Kategorie, Preis) VALUES ('Mai', '2014', 'Konzertkarte', 'Freizeit', '25,00');")
    _SQLite_Exec(-1, "INSERT INTO MonDB(Monat, Jahr, Grund, Kategorie, Preis) VALUES ('Mai', '2015', 'Konzertkarte', 'Freizeit', '20,00');")
    _SQLite_Exec(-1, "INSERT INTO MonDB(Monat, Jahr, Grund, Kategorie, Preis) VALUES ('Mai', '2015', 'Sportwette', 'Freizeit', '4,99');")

    [/autoit] [autoit][/autoit] [autoit]

    _SQLite_Query($hDB, "SELECT SUM(Preis) AS Preis FROM MonDB WHERE Monat LIKE '" & $sMon & "' GROUP BY '" & $sMon & "'", $QueryMonat)
    _SQLite_FetchData($QueryMonat, $aMonat, False, False)
    MsgBox(0, "", StringReplace($aMonat[0], ".", ","))

    [/autoit]

    Bei mir kommt immer 49,0 statt 49,99 raus :(

  • Stringtypen werden in SQL in Anführungszeichen gesetzt.
    Zahlentypen nicht.
    Darüber hinaus ist das Dezimaltrennzeichen der Punkt und nicht das Komma (das ist der Grund für dein Problem).

    Des Weiteren: Like wird zur Überprüfung von Zeichenketten mit Wildcards verwendet.
    Wenn, wie bei dir, keine Wildcards verwendet werden nimmt man das ganz normale =.

  • mit Round(20.00) <- Glaube ich, guck einfach mal nach, wie die Func aufgebaut ist
    oder mit StringSplit(String(20.00), ".")[1]
    ^- String(20.00) gibt "20.00" zurück, und StringSplit nimmt das erste vor dem ".", also 20.

    PS: Der 0. Rückgabewert von StringSplit ist die Anzahl der Strings.

    EDIT: Nein; String macht aus dem 20.00 schon "20", finde ich etwas blöd :/

    Spoiler anzeigen

    Überraschung!


    MfG Donkey

  • @ProgrammingDonkey Es geht hier um SQL, nicht um AutoIt ;)

    Natürlich gehts hier um Autoit!
    Der Threadstarter möchte das rechnerisch korrekte SQL Ergebnis schlichtweg optisch anderst (mit 2 Dezimalstellen) in seiner Ausgabe darstellen. Dafür wurde die Funktion stringformat(...) erfunden.

    [autoit]


    $test = StringReplace(StringFormat("%.2f", 20.5),".",",")
    ConsoleWrite($test & @CRLF)
    $test = StringReplace(StringFormat("%.2f", 20.55),".",",")
    ConsoleWrite($test & @CRLF)
    $test = StringReplace(StringFormat("%.2f", 20.555),".",",")
    ConsoleWrite($test & @CRLF)
    $test = StringReplace(StringFormat("%.2f", 20),".",",")
    ConsoleWrite($test & @CRLF)

    [/autoit]
  • Wenn man mit monetären Werten zu tun hat, sollte man es tunlichst vermeiden diese als Gleitkommazahlen zu speichern.
    Das kann zu binären Rundungsfehlern führen, welche gerade bei Geldbeträgen unbedingt vermieden werden sollten.
    Normalerweise nimmt man stattdessen Festkommazahlen.
    Sqlite besitzt leider keinen solchen Typ (auch wenn der Datentyp "Decimal" dies vermuten lässt).
    Ein üblicher Ausweg ist es daher Euro in Cent umzurechnen (also mal 100) und diese als Integer zu speichern und damit weiter zu rechnen.
    Erst in der Ausgabe wird dann noch ein Komma hinzugefügt.

    Prinzipiell wäre das mit der Ausgabe kein Problem wenn denn die printf-Funktion standardmäßig aktiviert wäre.
    Ist sie leider aber nicht und nicht jeder wird sich seine sqlite3.dll mit der entsprechenden Option selbst kompilieren.
    Daher muss man bei der Ausgabe ein bisschen mehr Aufwand treiben.

    Hier mal ein Beispiel für die Handhabung von Geldbeträgen als Integer und deren Ausgabe auf zwei Nachkommastellen:

    Geldbeträge in Sqlite als Integer
    [autoit]

    #include <SQLite.au3>
    #include <SQLite.dll.au3>

    [/autoit] [autoit][/autoit] [autoit]

    _SQLite_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    Global $h_DB = _SQLite_Open() ; erzeugt temporäre DB

    [/autoit] [autoit][/autoit] [autoit]

    ; Tabelle erzeugen
    _SQLite_Exec($h_DB, "CREATE TABLE MonDB (ID INTEGER PRIMARY KEY, Monat Text, Jahr Text, Grund Text, Kategorie Text, Preis INTEGER);")

    [/autoit] [autoit][/autoit] [autoit]

    ; Da monetäre Werte wie Festkommazahlen berechnet werden sollen, wird ein Trigger zur Umrechnung von Float-Preisen in Cent-Integer implementiert:
    _SQLite_Exec($h_DB, "CREATE TRIGGER AddMonetaryValue " & _
    "AFTER INSERT ON MonDB " & _
    "FOR EACH ROW " & _
    "BEGIN " & _
    "UPDATE MonDB SET Preis = NEW.Preis * 100 WHERE ID = NEW.ID; " & _
    "END;")

    [/autoit] [autoit][/autoit] [autoit]

    ; Tabelle mit Daten füllen:
    _SQLite_Exec($h_DB, 'insert into mondb ("Monat", "Jahr", "Grund", "Kategorie", "Preis") values ("Februar", "2015", "Tanken", "Auto", 48.34);' & _
    'insert into mondb ("Monat", "Jahr", "Grund", "Kategorie", "Preis") values ("September", "2015", "Reinigung", "Auto", 78.5);' & _
    'insert into mondb ("Monat", "Jahr", "Grund", "Kategorie", "Preis") values ("Mai", "2014", "Konzertkarte", "Freizeit", 25.00);' & _
    'insert into mondb ("Monat", "Jahr", "Grund", "Kategorie", "Preis") values ("Mai", "2015", "Konzertkarte", "Freizeit", 20.00);' & _
    'insert into mondb ("Monat", "Jahr", "Grund", "Kategorie", "Preis") values ("Mai", "2015", "Sportwette", "Freizeit", 4.99);')

    [/autoit] [autoit][/autoit] [autoit]

    ; Monatssummen bilden:
    _SQLite_ShowResult("SELECT Monat, CAST(SUBSTR(SUM(Preis) * 100, 1, LENGTH(SUM(Preis) * 100.0)-6) AS INTEGER) || ',' || SUBSTR('000' || CAST(SUM(Preis) AS INTEGER), -2, 2) AS Summe FROM mondb GROUP BY Monat;")

    [/autoit] [autoit][/autoit] [autoit]

    ; alles wieder ordnungsgemäß schließen:
    _SQLite_Close($h_DB)
    _SQLite_Shutdown()

    [/autoit] [autoit][/autoit] [autoit]

    Func _SQLite_ShowResult($s_Query, $h_DB = -1)
    Local $iR, $iC, $aRes
    _SQLite_GetTable2d($h_DB, $s_Query, $aRes, $iR, $iC)
    _ArrayDisplay($aRes)
    EndFunc ;==>_SQLite_ShowResult

    [/autoit]