Wie kann ich NULL in sum abfangen

Liebe/-r Experte/-in,
ich habe ein Problemchen und dazu bräuchte ich Deine Hilfe. Für die Mühe bedanke ich mich schon mal im vorraus.

Für unseren Verein programmiere ich gerade eine Fahrtkostenverwaltung.
Dazu habe ich die Tabelle Fahrtkosten mit id, datum, km und grund gebaut.
Bei Grund habe ich 3 Zustände. Einmal keine FK 999 (Übungsleitter stellt keine Forderung, fürs FA müssen die aber trotzdem erfasst werden) 998 für Kurz-Fahrten zB um im Freibad einen Stand auf zu bauen.
Der Rest ist für Fahrten die normal/korrekt abgerechnet werden.

Nun habe ich einen Filter eingebaut, wo ich Quartal und Jahr oder jeweils Alle wählen kann.

In der Übersicht habe ich dann folgendes sql-Statement:

SELECT 2*SUM(IF(grund=‚999‘, km,0)) AS keinefahrtkosten,
2*SUM(IF(grund=‚998‘, km,0)) AS werbungsfahrtkosten,2*SUM(IF(grund!=‚998’and grund!=‚999‘, km,0)) AS normalfahrtkosten FROM fahrtkosten where if(".$quartal."=0,1,quarter(fahrtkosten.datum)=".$quartal.") and if($jahr=0,1,Date_Format(fahrtkosten.datum,‘%Y’) = ‚".$jahr."‘)

Klappt soweit im Normalfall.

Nun möchte ich den Fall abfangen, dass keien Daten in der DB sind (Bsp 3 Quartal 2010 oder 1. Quartal 2008)

if(mysql_num_rows($ms_fahrtkosten)==0 )
echo „Für den gewählten Zeittraum sind keine Fahrtkosten erfasst.“;
else
{
while($ausgabe_fahrtkosten=mysql_fetch_assoc($ms_fahrtkosten))
{…

Und da sitzt der Knackpunkt. sum() liefert mir bei fehlenden Daten eine Zeile mit „NULL“

Den Filter für die Jahre kann ich zwar aus der DB generieren, aber die Quartale nicht ohne weiteres.

Sonst müsste ich jedesmal nachfragen, ob das Quartal des gewählten Jahres existiert und ob da Werte drin sind.

Kann ich irgendwie die NULL abfangen? Also sowas wie in Excel summewenn…

Mit einem group by komme ich nicht weiter. Als Ergebnis möchte ich halt max. drei Zeilen haben:
Werbungsfahrtkosten: 120€
Keine Fahrtkosten: 12€
normale fahrtkosten 1222€

Gruß aus T
Oliver

Hallo,

Sonst müsste ich jedesmal nachfragen, ob das Quartal des
gewählten Jahres existiert und ob da Werte drin sind.

Naja, aber die zusätzliche Spalte mit count(*) oder count(km) für die Anzahl der Datensätze, die auf den WHERE-Ausdruck passen, ist doch nicht das Problem ? Oder habe ich da etwas falsch verstanden ?

Kann ich irgendwie die NULL abfangen? Also sowas wie in Excel
summewenn…

Also das wenn eine Summe NULL ist, die Zeile nicht kommt, sollte mit HAVING 2*SUM(IF(grund=‚999‘, km,0)) IS NOT NULL , das ganze ggfs. mit AND oder OR für alle 3 Spalten.

Alex

Hallo alex,
danke für die superschnelle Antwort!!
count hilft mir nicht weiter, denke ich, da lt. Doku. sum
NULL liefert wenn die beiden summanden nicht existieren.
Wenn ichs direkt im phpmyadmin eingebe bekomme ich als Ergebnis einen Datensatz zurück.
Row0: Null null null
Also Bedingung nicht erfüllt. while schleife wird ausgeführtund ich habe 3 Zeilen mit 0,00€

Having? Das kenne ich nicht, ist also ein Ansatz. Danke!

Hallo,

Hallo alex,
danke für die superschnelle Antwort!!
count hilft mir nicht weiter, denke ich, da lt. Doku. sum
NULL liefert wenn die beiden summanden nicht existieren.
Wenn ichs direkt im phpmyadmin eingebe bekomme ich als
Ergebnis einen Datensatz zurück.
Row0: Null null null

Ja, aber in der count(*) Spalte sollte halt 0 stehen, weil kein Datensatz auf WHERE passt, das kann man dann ja in PHP abfragen, und dann die entsprechende Meldung zeigen, also da sollte dann z.B. 0 NULL NULL NULL rauskommen, und wenn die count(*) Spalte 0 ist, gab es keinen Datensatz, der aufs WHERE gepasst hat.

Also Bedingung nicht erfüllt. while schleife wird
ausgeführtund ich habe 3 Zeilen mit 0,00€

Having? Das kenne ich nicht, ist also ein Ansatz. Danke!

Damit sollte sich die Zeile komplett filtern lassen…

Alex

Hi,

ich denke ich probiers mit having…

Count zählt, wenns ichs richtig verstanden habe, die wiledurchläufe.

Während mit having vorab abgewürgt wird, wenns nicht passt. Damit müsste doch count relativ langsam sein, da das fetch assoc erstmal durchläuft und dann abgewürgt wird.
Oder heisst das sowas wie

SELECT 2*SUM(IF(grund=‚999‘, km,0)) AS keinefahrtkosten,count(id) as $anzahl
… where if(".$quartal."=0,1,quarter(fahrtkosten.datum)=".$quartal.") and if($jahr=0,1,Date_Format(fahrtkosten.datum,’%Y’) = ‚".$jahr."‘)

Hi ,

ich glube ichhabs mit having lösen können. Schneltest war positiv. Muss es noch genauer testen, aber soscheints zu gehen:

SELECT 2*SUM(IF(grund=‚999‘, km,0)) AS keinefahrtkosten,count(km),2*sUM(IF(grund=‚998‘, km,0)) AS werbungsfahrtkosten,2*SUM(IF(grund!=‚998’and grund!=‚999‘, km,0)) AS einsatzfahrtkosten FROM fahrtkosten where if(1=0,1,quarter(fahrtkosten.datum)=1) and if(2010=0,1,Date_Format(fahrtkosten.datum,‘%Y’) = ‚2010‘) having 2*SUM(IF(grund=‚999‘, km,0))!=‚NULL‘ and 2*SUM(IF(grund=‚998‘, km,0))!=‚NULL‘ and 2*SUM(IF(grund!='998’and grund!=‚999‘, km,0))!=‚NULL‘

Also nochmals ein fettes xxl thanx!

Hallo Oliver,
ich konnte jetzt nicht Dein ganzes Programm nachvollziehen. Probiere aber mal einfach: „NULL“ dürfte das Gleiche wie „“ sein bzw. auch mit
if (!isset($…)) oder das sollte auch mit einem einfachen if abgefangen werden können.
if ($sum) … „NULL“ müsste wie ein false reagieren.

Musst einfach mal probieren.
Mehr kann ich in der Kürze auch nicht sagen. Habe dieses Problem selbst noch nicht gehabt.

Viele Grüße und viel Erfolg

Werner

Hallo Werner,
danke für Deine SUperschnelle Antwort. Having heisst das Zauberwort.

Kannte ich auch nicht. Aber einer war noch schneller wie Du. :wink:

Also das Statement wie gehabt und zum Schluss having (sum(if…)!=„Null“)

Gruß
Ollie

Ich kann mich leider momentan nicht darum kümmern.
Damit Sum funzt sollten alle Spalten die Zahlen enthalten auf Integer mit DEFAULT = ‚0‘ stehen.
Sollen Zeilen die einen NULLwert enhalten gefiltert werden nutzt man: WHERE ‚spaltenname‘ IS NULL/IS NOT NULL
Dazu müssen die Spalten als DEFAULT = NULL definiert sein und nicht auf NOT NULL stehen.

http://dev.mysql.com/doc/refman/5.0/en/working-with-…

Das Statement ließe sich mit GROUP auf eine Abfrage reduzieren - Doch das funktioniert :smile:

was soll bei NULL passiern?
Kennst du UNION-Abfragen?
die könnten helfen.
für alle 3 individuell abfragen, die per UNION verbinden - ein ergebnis.

ps: ich hoffe du hast $quartal etc NICHT aus dem web - sonst hast du die geilste SQL-injection gebaut… stell dir vor, $quartal ist „;DROP TABLE fahrtkosten;“

Hi Leif,
danke für Deine schnelle Antwort.
group by geht nicht, da ich nicht genau drei Zustände habe, sondern
nur 3 Zstände filtern möchte.

Also nicht nur Zustand 1 und Zustand 2 und Zustand 3, sondern Zustand
1, Zustand 2 und alle anderen.

Und wie soll ich dem Programm mitteilen, dass das Quartal 3 von 2007
nicht in der DB ist? Oder Quartal 4 2010.

Und nicht die Spalte hat Null, sondern die Summe. having ist glaube
ich mein Zauberwort.

Gruß aus T
Oliver

Hi Danke für Deine schnelle Antwort.

also ich habe was neues gelernt. Mein gesuchtes Zauberwort heisst „having“

Also das Statement wie gehabt und zum Schluss having (sum(if…)!=„Null“)

NULL sollte abgefangen werden. sum liefert ein „NULL“ wenn die Summanden nicht da sind. Also Quartal 3 2010

Union oder auch group by geht nicht, group by geht nicht, da ich nicht genau drei Zustände habe, sondern
nur 3 Zustände filtern möchte.

Also nicht nur Zustand 1 und Zustand 2 und Zustand 3, sondern Zustand
1, Zustand 2 und alle anderen.

Zur sql-Injection:

Wie soll das gehen? Ich habe:

where if(".$quartal."=0,1,quarter(fahrtkosten.datum)=".$quartal.")

Also wenn Fahrtkosten=0 dann nichts sonst …

Ein drop table geht doch nicht innerhalb eines where, oder?

Zudem müsste der Anwender in den geschlossenen Mitgliederbereich kommen und die Datenbankstruktur kennen.

Oder stehe ich gerade vorm Wald?

Die km will ich mir auf Dauer tatsächlich aus dem Web von opengdb holen.

Gruß aus T
Oliver

Hallo Oliver

da die Abfrage zu einer Sum immer eine row zurückliefert, würde ich meine php abfrage nicht auf mysql_num_rows aufbauen, sondern einfach in deiner while schleife, die ergebniss auf NULL prüfen und erst wenn die Ergebnisse nicht NULL sind, eine echo ausgaben machen

ich hoffe, ich konnte helfen

gruß silvio

Hi Silvio,

danke für Deine Antwort.
Having ist mein Zauberwort. SQL_Abfrage wie gehabt und dann having(sum(if…))!=„NULL“)

Kannte ich auch noch nicht, macht aber genau das, wwas ich möchte.

While ging auch, klar. Aber so kann ichs auf den sql-Server abladen.
Gruß aus T
Oliver

hi,
SQL Injection:
es ist egal ob das ein geschützter Bereich ist…

http://www.tizag.com/mysqlTutorial/mysql-php-sql-inj…
bzw.:
http://at2.php.net/manual/en/security.database.sql-i…

verwend bitte
http://at2.php.net/mysql_real_escape_string

Alternativ kannst Du auch Queries vorbereiten und mit Parametern ausführen:
http://at2.php.net/manual/en/function.maxdb-prepare.php

Hallo,
danke Danke. Das sind erstmal viele Infos und massig.
Letzte Frage:
Geschlossener Bereich egal? Per htaccess Bereich geschützt, da müsste ja schon einer mit Zugriff die Abfrage sabotieren oder?

PS Re^2: Wie kann ich NULL in sum abfangen
SO ists besser:

$sql_quittungen=sprintf(„select sum(wert) as geswert,quittungskategorie.name from quittungen,quittungskategorie where quittungen.kategorie_id=quittungskategorie.id and if(%s=0,1,quarter(quittungen.datum)=%s) and if(%s=0,1,Date_Format(quittungen.datum,’%Y’) = ‚%s‘) group by kategorie_id having sum(wert)!=‚NULL‘“,mysql_real_escape_string($quartal),mysql_real_escape_string($quartal),mysql_real_escape_string($jahr),mysql_real_escape_string($jahr);
$ms_quittungen=mysql_query($sql_quittungen));
$quittungszahl=mysql_affected_rows();

naja
das risiko ist daß jemand vollen zugang zu deinen daten bekommt…
bzw über evtl. bugs auch andre sachen tun kann…

better safe than sorry :smile:

sprintf seh ich jetz nicht so als nötig an, das real_escape macht die sache jedoch _wesentlich_ sicherer - alles gute weiterhin!

Danke!

Hatte nicht wirklich drüber nachgedacht, Da es via htaccess und gutem Passwort geschützt ist. Aber stimmt. bugs und menschliches versagen.

Gibt ja immer noch das Klischee von der Tippse, die sich das Passwort auf den Monitor klebt. :wink:

Probiers mal mit dreifachem gleichzeichen ===

$ausgabe_fahrtkosten = mysql_fetch_assoc($ms_fahrtkosten);

if($ausgabe_fahrtkosten[‚keinefahrtkosten‘]===null) {

} else {

}

Alternative

SELECT 2*SUM(IF(grund=‚999‘, km,0)) AS keinefahrtkosten,

ISNULL(2*SUM(IF(grund=‚999‘, km,0))) AS keinefahrtkostennull,

2*SUM(IF(grund=‚998‘, km,0)) AS werbungsfahrtkosten,2*SUM(IF(grund!=‚998’and grund!=‚999‘, km,0)) AS normalfahrtkosten FROM fahrtkosten where if(".$quartal."=0,1,quarter(fahrtkosten.datum)=".$quartal.") and if($jahr=0,1,Date_Format(fahrtkosten.datum,‘%Y’) = ‚".$jahr."‘)

und dann keinefahrtkostennull checken