Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   count mit 0 (https://www.delphipraxis.net/187205-count-mit-0-a.html)

p80286 6. Nov 2015 15:56

Datenbank: oracle • Version: 11 • Zugriff über: egal

count mit 0
 
hallo zusammen,
der Titel ist u.U. wenig aussagekräftig, darum versuche ich das mal zu beschreiben.
Ich habe eine Abfrage in der ich Zähle:
SQL-Code:
select Abteilung,Gegenstand,count(key)
from tt
where zeit between(startdate,eddate)
group by Abteilung,Gegenstand
funktioniert auch gut, es gibt nur ein Problem, wenn es im Zeitraum,in einer Abteilung keinen Gegenstand gibt, gibt es keine Ergebniszeile in der Ausgabe, mein Chef möchte aber wissen, das es nichts gibt
z.B.
Code:
Einkauf Anforderungen 128
Verkauf Aufträge 12
Lager Eingänge 0
Personalabteilung Kündigungen 12
und nicht

Code:
Einkauf Anforderungen 128
Verkauf Aufträge 12
Personalabteilung Kündigungen 12
Wie erreiche ich das?
Gruß
K-H

Nachtrag:
ein Kollege hat mir über die Schulter geschaut und was von NVL und Coalesce gemurmelt, aber geht das denn?
Mir fehlt doch der ganze Satz und nicht nur ein Feld?

Jumpy 6. Nov 2015 16:18

AW: count mit 0
 
Wenn du den Zeitraum filterst und in dem Zeitraum nichts ist, kriegste auch nix. Du musst erstmal einen Distinct Select über alle Abteilungen/Gegenstände machen und dass dann z.B. mit dem bisherhigen Joinen. Oder einen Subselect machen, aber vllt. langsamer:

Code:
Select Distinct Abteilung, Gegenstand,
(Select count(*) from tt where Abteilung=tt1.Abteilung and Gegenstand=tt1.Gegensand) as Anzahl
from tt as tt1

Aurelius 6. Nov 2015 16:27

AW: count mit 0
 
Jumpys Lösung sollte bereits funktionieren. Aus der Hüfte geschossen wäre folgende Variante auch möglich:

Code:
SELECT LagerGegenstand.Abteilung, LagerGegenstand.Gegenstand, count(*)
FROM
   (SELECT DISTINCT Abteilung, Gegenstand FROM tt) as LagerGegenstand LEFT JOIN tt ON (LagerGegenstand.Abteilung = tt.Abteilung AND LagerGegenstand.Gegenstand = tt.Gegenstand AND tt.zeit between(startdate,eddate))
GROUP BY LagerGegenstand.Abteilung, LagerGegenstand.Gegenstand;
//bzw. ohne das "as", ist ja Oracle

nahpets 6. Nov 2015 18:42

AW: count mit 0
 
Solche "Spielereien" Oracle ich in der Regel so in der Art:
SQL-Code:
select Abteilung, Gegenstand, Sum(Anzahl) as Anzahl from (
  select Abteilung, Gegenstand, count(key) as Anzahl
  from tt
  where zeit between(startdate,eddate)
  group by Abteilung, Gegenstand
  union all
  select disitinct Abteilung, Gegenstand, 0 as Anzahl
  from tt
)
group by Abteilung, Gegenstand

Dejan Vu 6. Nov 2015 19:25

AW: count mit 0
 
Du müsstest eine Tabelle aller Abteilungen und Gegenstände haben (wenn du auch 0-Werte für die Gegenstände haben willst).

Bleiben wir mal bei Abteilungen. Dann machst Du ein LEFT JOIN deiner Abteilungen auf deine Auswertung und bekommst so automatisch alle Abteilungen und -falls Daten vorhanden sind- eben auch Werte. Wenn nicht, dann steht da NULL, aber das kannst du dann ja auf 0 ändern.
So z.B.:
SQL-Code:
select A.Abteilung,
       S.Gegenstand,
       Count(S.Key)
  from AlleAbteilungen A
       left join tt s on A.Abteilung = s.Abteilung
 where zeit between(startdate,eddate)
 group by s.Abteilung,s.Gegenstand
Jumpy's Lösung ist auch cool, würde aber etwas länger dauern, wenn in TT sehr viele Zeilen sind und kein Index auf der Abteilung/Gegenstand ist. Dann muss er ja vorher die gante Tabelle abgrasen, um alle Abteilungen zu bekommen. Außerdem (mecker mecker) funktioniert das nicht, wenn eine Abteilung X, die angezeigt werden soll, bisher noch keine Werte hat.

jobo 6. Nov 2015 23:59

AW: count mit 0
 
und noch eins:
Code:
select Abteilung,
       Gegenstand,
       sum(case
             when Zeit between :startdate and :enddate
             then 1             
             else 0
           end)
  from tt
 group by Abteilung, Gegenstand
Macht garantiert einen full scan (aber nicht mehr), eignet sich wohl am ehesten, wenn eh keine Indizes auf den abgefragten Feldern sind und die anderen Vorschläge auch bereits einen Fullscan machen.
Aber ich schätze, wenn es hier um Abteilungen geht, sind es eh keine Riesenmengen und Performance ist bedeutungslos.

Dejan Vu 7. Nov 2015 08:26

AW: count mit 0
 
Erstens macht meine Lösung keinen full scan und zweitens würde auch hier eine Abteilung erst dann in der Statistik auftauchen, wenn Daten vorhanden sind.

jobo 7. Nov 2015 14:18

AW: count mit 0
 
Zitat:

Zitat von Dejan Vu (Beitrag 1320808)
Erstens macht meine Lösung keinen full scan und zweitens würde auch hier eine Abteilung erst dann in der Statistik auftauchen, wenn Daten vorhanden sind.

Noch kein Kaffee gehabt oder schon zuviel? ;)
Ich habe mich überhaupt nicht zu Deiner Lösung geäußert. Falls Du Dich zu meiner geäußert hast, würde ich sagen, das musst Du noch mal präziser formulieren, wir anfangen zu streiten, äh ich meinte bevor ich darauf eingehe.

Dejan Vu 7. Nov 2015 20:26

AW: count mit 0
 
Ich wollte halt mitreden. :oops:

p80286 9. Nov 2015 09:58

AW: count mit 0
 
Hallo Zusammen,
erst mal vielen Dank für die Rückmeldungen.
@napeths Die Möglichkeit scheint mir im Augenblick die sinnvollste, vor allem weil sie "selbstdokumentierend" ist.
@jobo ist das eine Möglichkeit aus der Kiste "So geht's auch"? scheint mir ein bißchen Umständlich liefert aber das richtige Ergebnis.
@Jumpy ,Aurelius,Dejan Vu wenn ich das richtig verstanden habe, Wird hierbei ein "Abteilungs/Gegenstand"-Platzhalter ohne ein Zählergebnis (null) geliefert. Daraus kann man dann 0 basteln.

Ich denke, es ist klar das die Originalabfrage etwas komplexer ist, darum muß ich da ein wenig Zeit, auch für die Performance, investieren um die optimale Lösung zu implementieren.
Wenn ich soweit bin, melde ich mich nochmals.

Euch allen vielen Dank!

K-H

jobo 9. Nov 2015 10:44

AW: count mit 0
 
Zitat:

Zitat von p80286 (Beitrag 1320909)
@jobo ist das eine Möglichkeit aus der Kiste "So geht's auch"? scheint mir ein bißchen Umständlich liefert aber das richtige Ergebnis.

Ja, wie Du festgestellt hast, es geht auch. :)
Der Grundgedanke ist: Wenn ich sowie alle "Abteilungen" oder was auch immer anzeigen muss(!), hab ich an der Stelle eh einen Fullscan (oder sowas in der Art, falls "alle Abteilungen" ein Zwischenergebnis aus einem View oder Subselect sind). Wenn das also stattfindet, kann ich die engine "unterwegs" an der Stelle direkt mitrechnen lassen, statt erneut diejenige Untermenge anzuflanschen und zu zählen, die mich am Ende interessiert.
So wird ein 2. Scan, Range/Hash was auch immer vermieden.

Ich hab mir nicht die Mühe gemacht, die Statements zu testen, aber auf die ein oder andere Art müssen auch die anderen Statements ihre Grundmenge irgendwo herbekommen und zwar unconditional und mglw auch ohne verfügbar Indizierung. Schau Dir den Ausführungsplan der Varianten an- falls es überhaupt eine Rolle spielt. Ich denke meine Variante dürfte da relativ übersichtlich sein.
Wenn Dein Originalstatement sehr komplex ist, sind die Unterschiede der Ausführungspläne ggF. schwer zu vergleichen, wenn dann noch die Datenmenge groß ist, bietet sich als erstes ein Blick auf die Laufzeit an. Das schnellste gewinnt.

Das Case When sieht natürlich nicht hübsch aus, die Lösung ist einfach straight forward. Die guten ins Töpfchen, die schlechten ..

p80286 9. Nov 2015 14:49

AW: count mit 0
 
Zitat:

Zitat von jobo (Beitrag 1320917)
.. bietet sich als erstes ein Blick auf die Laufzeit an. Das schnellste gewinnt.

Jo, so sehe ich das auch erst einmal.
Was gewöhnungsbedürftig ist, daß auf den ersten Blick nicht gezählt wird was man zählen will. Da muß man sich erst einmal etwas bei denken:mrgreen:

Gruß
K-H

Dejan Vu 10. Nov 2015 06:54

AW: count mit 0
 
In meinen Tabellen habe ich selten eine 'Abteilung', sondern eigentlich immer nur einen FK auf eine separate Tabelle 'Abteilungen', das ist ja normal. Ergo habe ich bereits eine Tabelle aller Abteilungen.

Weiterhin habe ich 'Auswertungsgruppen'. Dort lege ich ab, welche Abteilungen (Produkte, Personen, egal) zusammengefasst werden sollen. So habe ich z.B. eine Auswertungsgruppe 'Alle aktiven Abteilungen', oder 'Meine Top-Produkte' oder 'Personen aus dem 3.Stock'.

Nun kann ich über diese Gruppen beliebige Auswertungen fahren, sodaß immer alle Mitglieder dieser Gruppe in den Auswertungen auftauchen, auch wenn noch keine Daten angefallen sind.

Code:
select A.Name,
       coalesce (sum (d.Irgendwas), 0) as Ergebnis
  from Abteilungsgruppe Ag
       join Abteilung A on Ag.AbteilungsID = A.ID
       left join Daten d on d.AbteilungsID = A.ID
 where d.Datum between :Start and :Ende
   and Ag.ID = 23 --  23 sei jetzt mal die GruppenID der Gruppe 'Alle aktiven Abteilungen'
Und nun kann ich einfach den Zeitraum und die Auswertungsgruppe parametrieren und dann habe ich einen Report, der mir für jeden beliebigen Zeitraum und jede beliebige Abteilungsgruppe eine Auswertung liefert.

Über Trigger in der Auswertungsgruppe kann ich zudem steuern, ob (und ggf das) eine Abteilung nur in einer Gruppe sein darf oder nicht.

Wenn ich dieses Pattern auf alle meine Daten lege, stellen sich mir diese Fragen hier gar nicht mehr, weil alle meine Reports automatisch schon all das anzeigen, was gewünscht ist. Und da die Auswertungsgruppen vom Kunden editierbar sind, kann er sich seine Abteilungsauswertungen auch beliebig zusammenstellen. Und ja: Natürlich gibt es noch Auswertungen je Tag und über alle Gruppen (Achtung! Wenn Gruppen nicht disjunkt sind, stimmt die Summe nicht).


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz