balgor
Goto Top

Crystal Reports - Anzahl eindeutiger Werte - Ergebnis ungenau

Hallo,

ich habe mal wieder eine Frage aus Crystal Reports, mit einfachen Probleme gebe ich mich da nicht mehr ab. face-smile
Folgender Sachverhalt:

Unser ERP-System erzeugt eine übergreifende VorgangsID, unter dieser VorgangsID können sich weitere Belege befinden z.B. Aufträge, Rechnungen, Gutschriften und mehr.

Ich wollte jetzt für jeden Monat die Anzahl der eindeutigen VorgangsIDs pro Filiale zählen und ein Gesamt pro Zeile und Spalte haben.
So sollte es aussehen:
	Jan	Feb	Mar	etc.	Ges:
Fil1	 12	  9	  6		  27
Fil2	  8	 10	 11		  29
Fil3	  7	  6	  7		  20
Ges:	 27	 25	 24		  76
Leider kommt es jetzt vor, dass z.B. der Auftrag am 30. Januar erzeugt wird, aber die Rechnung erst am 02. Februar geschrieben wird.
Dadurch ist die VorgangsID einmal im Januar vorhanden und einmal im Februar, evtl. gabs im März sogar noch eine Gutschrift zu diesem Vorgang und schon ist die VorgangsID in 3 Monaten vorhanden.

Auf die einzelnen Werte bin ich auf folgendem Weg gekommen am Beispiel vom Monat März - kurz:
-> Laufende Summe-Felder
-> Feld für Gruppenergebnis = DB.VorgangsID
-> Art des Gruppenergebnisses = Anzahl eindeutiger Werte
-> Auswerten = Formel verwenden - mal am Beispiel vom Monat März
{DB.DATUM} >= (dateadd("m",2,minimum(yeartodate)))and  
{DB.DATUM} <= (dateadd("m",3,minimum(yeartodate))-1)  
-> Zurücksetzen = Bei Änderung von Gruppe = Gruppe 1: DB.Filiale
Die Formel habe ich in den Gruppenfuß gepackt.

Das gleiche habe ich für die Gesamtsumme im Berichtsfuß mit einem ähnlichen Laufende Summe-Feld gemacht, nur mit einer kleinen Änderung.
-> Zurücksetzen = Nie

Dadurch ist mir irgendwann aufgefallen, dass wenn ich die Summe des Januars für die einzelnen Filialen selber zusammen rechne, sie größer ist als die Gesamtsumme durch die Formel.
Wie es leider im Anschluss aussieht:
	Jan	Feb	Mar	etc.	Ges:
Fil1	 12	  9	  6		  27
Fil2	  8	 10	 11		  29
Fil3	  7	  6	  7		  20
Ges:	 19	 20	 18		  57
Begründung, sieh oben. Die Gesamtsumme durch die Formel (Beispiel März: 18) sollte der richtige Wert sein. Jetzt muss ich es nur noch schaffen das die Werte für die einzelnen Filialen/Monate stimmen.

Mein Gedanke war es nur das erste Auftreten der VorgangsID zu zählen. Um dabei auf mein Beispiel vom Anfang zurück zu kommen: Der Vorgang würde dem Januar zugerechnet und die Rechnung bzw. die Gutschrift im Februar und März werden nicht gezählt. - Aber wie mache ich das, jemand eine Idee?

Bevor jemand auf die Idee kommt zu fragen, warum ich nicht nicht die AuftragsID oder RechnungsID zähle. Es gibt leider Konstellationen in denen ich z.B. keine AuftragsID habe.
Mit der VorgangsID habe ich wirklich jede Konstellation mit abgefangen und bekomme die am ehesten korrekten Zahlen.

Mfg Balgor

Content-Key: 4396924172

Url: https://administrator.de/contentid/4396924172

Printed on: April 26, 2024 at 16:04 o'clock

Member: ukulele-7
ukulele-7 Oct 25, 2022 at 15:04:00 (UTC)
Goto Top
Ich kann dir da jetzt nur aus SQL Sicht weiter helfen, aber das Prinzip ist das Selbe. Du hast zu einem Datensatz (Vorgang) mehrere 1:n verknüpfte Datensätze, in deinem Fall wohl ggf. AuftragsID, RechnungsID, ggf. GutschriftID. Da AuftragsID nicht zwingend gegeben ist aber RechnungsID ja noch nicht existieren könnte würdest du vermutlich einfach den ersten Datensatz nehmen, also nach Datum sortiert, und den dann zählen. Am einfachsten wäre es jetzt die anderen Datensätze weg zu lassen, also erstmal nach VorgangsID gruppieren und das Datum von AuftragsID, RechnungsID, GutschriftID auf den kleinsten Wert aggregieren. Dann hast du eine Tabelle mit einer Position pro AuftragsID und kannst entsprechend zählen bzw. wie bei dir pivotieren.
Member: it-frosch
it-frosch Oct 25, 2022 updated at 16:02:18 (UTC)
Goto Top
Hallo Balgor,

Mein Gedanke war es nur das erste Auftreten der VorgangsID zu zählen.
In die SQL Query (Datengrundlage des Reports) das einbauen.
SELECT A.vorgangidnr,A.EINTRAGDAT FROM TABLE A where A.EINTRAGDAT=(select min(B.eintragdat) from TABLE B where B.vorgangidnr=A.vorgangidnr)

Ich mache mir meist eine Query und vereinfache mir so den Reportbau.

Grüße vom it-frosch
Member: Crusher79
Crusher79 Oct 25, 2022 updated at 19:42:38 (UTC)
Goto Top
Ohne Query Eingriff hilgt nur eine Formel oder? Bin grad etwas eingerostet. Ist nur jetzt mal hart zusammengewürfelt!

Wenn die VorangsID das erstemal vorkommt kannst du Variable auf true setze. Oder eine als int auf 1.

Hier in den Beispiel geht es um die Prozente. Nur Beispiel. Wichtig ist WANN es auswertet. WhilePrintingRecords müsste auch bei dir passen.

Die Art der Variable ist wichtige, wenn man die auch in Unterberrichten nehmen will - dann wäre es Shared. Hab es dir mal so hier reingehauen! Passt natürlich nicht.

Ggf. musst du auch vorher noch eine Expression z.B. in den Gruppenkopf bringen, die die Variable zurück setzt! Damit geht es quasi immer los. Gruppenkopf könnte aber je nach Aufbau auch heissen, dass es immer auf Null/ 0/ Blank gesetzt wird und du nie ein Ergebnis bekommst!

Wie ist denn die Tabelle gruppiert? Wenn du die nach der VorgangsID gruppierst, wären doch bei jeden Durchgang nur alle Vorgänge zur der Nummer drin? In dem Fall über alle Monate hinweg. Willst du das nicht, kannst du den akt. Status auch in Variablen schreiben: Monat + Vorgang + Fil. Wenn die Variable immer überschrieben wird, hast du am Ende eine Var die den letzten Monat + Vorgang + Fil bereitstellt.

Das wäre zumindest durch das updaten bei durchlaufen der Gruppe am Ende dann eindeutig. Der letzt wert. Aber eben nur sowas wie Mai - 0815 - Fil_1

Es kann auch mehr als nur einen Gruppenkopf geben. Damit kannst du es verschachteln und so nach versch. Kriterien vor sortieren, bzw. eine Gruppe bilden.

Sorry, bin heute nicht ganz da. Mein Ansatz wären geeignete Gruppenköpfe (auch vor allem mehrere) und SUM Variablen.

Unseres war auf Line-Printer augerichtet. Ein Alptraum. Hab Mit POS und UNTERPOS ein Floats konstruiert und danach gruppiert. Sonst liefen auch die Daten kreuz und quer. Gruppen bilden ist sehr simpel. Die 2. Gruppe war eine spezielle LfdNr, die noch von Line Printing herrührt.

Die Zwischenergebnisse kannst du ja in VAR festhalten und am Ende als Summe ausgeben oder mittels "Shared" in einen Unterbericht ausgeben.

Auch wenn man Zeilen ausblendet, werden die Expressions ausgewertet. Auch bei vielen Gruppen musst du nicht zwangsläufig dir alle Werter so sichtbar runterdrucken lassen! Ausblenden und es ist übersichtlichert.

Sorry, mehr geht grad nicht.

Beispiel für Variablen:

WhilePrintingRecords;
Global NumberVar PrpRabattPerc;
if ({prp710_2.__satzart} ="RZ") then   
PrpRabattPerc := {prp710_2.rgrproz};

WhilePrintingRecords;
Shared StringVar PrpKunart;
Shared StringVar PrpKunart2;
Shared StringVar PrpKunart3;
//PrpKunart + ChrW(13) + PrpKunart2 + ChrW(13) + PrpKunart3;
PrpKunart;
Member: Crusher79
Crusher79 Oct 25, 2022 updated at 20:54:56 (UTC)
Goto Top
Der übersichthalber hier mein Zwischenstand:

Die Gruppen werden im Gruppenfuß in umgekehrter Reihenfolge geschlossen.

Gruppenkopf1: Sortiert nach Filiale - aufsteigend
Gruppenkopf2: Sortiert nach VorgangsID - aufsteigend
Gruppenkopf3: Sortiert nach Monat - absteigend
- Da die Reihenfolge umgedreht ist, wäre es immer der letzte Monat
- Wenn man sich Ergebnis + Monat merkt, wär das der letzte Monat in dem die VorangsID vorkommt

Durch die Gruppen sind wir nun immer noch zuerst im letzten Monat. VAR für Monat und Wert für VorgangVorhanden? können nun auf den Monat +1 gesetzt werden. Und zwar nur dann, wenn VAR Monat leer vorher leer war. Auch wenn die anderen Monate durchlaufen werden ändert sich hier nichts. Da wir uns innerhalb einer VorgangsID bewegen wäre das quasi unser Teilergebnis: Shared StringVar MAI := 1

WhilePrintingRecords;
Shared NumberVar MAI;
if (MAI =0) then MAI := 1;

Stimmt nicht ganz, man müsste alle 12 Monate vorbereiten und den jeweils richtigen durch die Expression updaten. Dann würde aber an dieser Stelle die MonatsVAR den letzten Monat beinhalten, wo dieser eine Vorgang vor gekommen ist.

Statt 12 x mal IF könnte man auch überlegen. Monat mit Num-Padding in eine StringVar zu packen und mit Ergebnis zu verketten: 051 = Im Mai einmal vorgekommen. Dann reicht es zu prüfen, ob die StringVar leer ist. Steht was drin, wurde schon was gefunden.

Zum zusammenfassen aller Vorgänge könnte man mit 12 VAR arbeiten. So etwas wie GesMAI. Die erste Variable sollte ja nur die Stelle festhalten, wo der Beleg das letzte mal vor gekommen ist.

Wenn an mit einen StringVar arbeitet, muss man den hier zerlegen und den Monaten gegenüberstellen. So dass das Ergebnis 051 mittels GesMAI := 1 in GesMAI landet.

05-1 braucht es eige. auch nicht. Wenn wir uns in der Gruppe bewegeen wäre das einfach der Monat, der als Ges<Monat> um +1 gezählt werden muss.

In dem Fall also einfach im Gruppenfuß immer die Ges<Monat> VAR mit den entsprechenden Teilergebnis updaten.

Am Ende hätte wir dann dein Ergebnis. Die Teilergebnis Varialben sind nur eine Hilfestellung und müssen nach dem Wechsel der VorangsID zurück gesetzt werden.


Ungefähr so. Nur ein Planspiel. Aber durch Gruppen und VAR kann man es schon eineutig lösen. Natürlich etwas schreibarbeit. Ich weiss nicht, ob es eine Function dafür gibt.

Mir fallen da gerade versch. Varianten ein.... Ich glaub ich brauch Hilfe face-big-smile .....
Member: Balgor
Balgor Oct 26, 2022 at 06:18:20 (UTC)
Goto Top
Hallo,

wow vielen Dank für all die Gedanken die ihr euch bereits dazu gemacht habt, vorallem Crusher79 ... ich hoffe ich habe dich damit nicht um deine Nachtruhe gebracht. face-smile
Mit Variablen habe ich auch schon kurz etwas versucht, bin dort aber nicht so versiert und bin irgendwann in einer Sackgasse gelandet.

Ich werde die Idee noch mal aufgreifen und versuchen sie umzusetzen, Rückmeldung kann allerdings etwas auf sich warten habe die nächste Zeit andere Projekte mit etwas größerer Priorität auf dem Tisch.
Member: ukulele-7
ukulele-7 Oct 26, 2022 at 08:42:34 (UTC)
Goto Top
Also wenn es darum geht ein SQL Query anzupassen kann ich helfen, bei @Crusher s Code bin ich leider eher raus face-wink

Wenn ich das richtig verstehe aggregierst du bisher gar nicht sondern joinst nur alle relationalen Datensätze. Wenn du nur zählen willst kannst du problemlos erst aggregieren (und dabei das früheste Datum wählen) und dann zählen. Wenn jetzt aber noch andere Informationen gebraucht werden für den Report dann gäbe es eventuell einen besseren Weg.


Zitat von @it-frosch:

SELECT A.vorgangidnr,A.EINTRAGDAT FROM TABLE A where A.EINTRAGDAT=(select min(B.eintragdat) from TABLE B where B.vorgangidnr=A.vorgangidnr)
Das würde ich nicht empfehlen, das wäre ein Subselect pro Datensatz und wird bei vielen Datensätzen richtig Performance ziehen.

Von dem was bisher geschrieben wurde tut es ein einfaches GROUP BY. Es gibt aber noch jede Menge andere Möglichkeiten (zumindest bei vollwertigem SQL).
Member: Crusher79
Crusher79 Oct 26, 2022 at 10:33:18 (UTC)
Goto Top
Entweder SQL oder fang langsam an.

Gruppe + Sort und dann mal andrucken was dann kommt. Du hast dann ein Gefühl auf welchen DS CR gerade steht. Wir hatten Line Print Problem. Als es auf Laserdruck geht. Leider hat ERP eine Printtabelle hart gefüllt. Die Reihenfolge konnte man nur bedingt umstellen - Pos Kennzeichen.

Um etwas nach hinten zu schieben hab ich mir den Wert in VAR schreiben lassen. Die Zeile selber ausgeblendet, damit es nicht doppelt kommt. Wichtig ist wie gesagt der Auswertzeitpunkg: WhilePrintingRecords.

Das Problem ist, dass man nicht alle Funktionen wie in einer Programmiersprache hat. Sonst müsste man es in einer Art Temp Tabelle schreiben. Unter CR GUI ist mir das nicht bekannt.

CR Array

Das hatte ich gestern auch im Hinterkopf. Du hast ja nur 3 Eckdaten: Fil, Vorgang und Zeitraum. Ein Array könnte auch sehr hilfreich sein!

Sonst müsstest du alles von Hand schreiben. Das wäre vor allem Redundant. Ein Array kann die Ergebnisse halten und man kommt einfacher ran. Zumindest wenn ihn mit Monat als INT automatisch anspricht.

Problem ist noch die Formatierung. Da ein Array kein DS an sich ist. Müsstest dann als statisch Chr(13) mit in die Ausgabe einbauen damit im Fuß die Daten so raus kommen. Fuß gibt es ja nur am Ende. Aber nicht nur einmal. Siehe meine Gruppen oben. Jede Gruppe hat auch immer einen Fuß.

Das ist halt wichtig zum Füllen und zurücksetzen der Variablen.

Normal müssten man hier beim Füllen das Arrays den Index auch aus Monat holen könnnen - 1...12. Du ahnst worauf ich hinaus will.

a[1] := "good";  
a[2] := "bye";  

@ukulele-7 SQL nochmal aufzugreifen: https://blogs.sap.com/2014/03/25/using-temporary-tables-with-crystal-rep ...

Sowas geht natürlich auch. Ggf. in Kombination.

Du solltest ggf. mal mit VAR, Array und den Auwertungszeitpunkt "spielen". Du brauhst schon ein Gefühlt dafür. Wenn zuviel tipperei im Spiel ist, überleg wie du es automtisieren kannst. Array Index automatisch anhand des Monats füllen z.B.

Wir haben INT, String. Können String Operationen machen. Es gebe hier mehr Ansätze.

Array: a{1]=2 <- 2x Mal im Monat 1 = Januar
String: 012 <- Mit Num-Padding wird Datum 2x stellig. 01 = Januar; 2 als Anzahl
String: 04 <- Irgendwas im April

"Irgendwas" klingt jetzt komisch. Soll nur die Moment des 1. auftretens festhalten. Am Ende wird abgerechnen und diese EINE Ereignis mit anderen für Monat/ Fil summiert.

Du ahnst vlt. worauf ich hinaus will

Aber auch wenn es Komplex ist, machen andere teils gegen Geld. In meinen ERP hab ich abenteuerliches gesehen. Allein Adressfeld mit 6-Zeilen. Mit oder ohne Strasse/ Plz. Da kam 1x halbe DIN A4 Seite zusammen!

Gefangen in der IF...ELSE Hölle. Darum hab ich dir oben ein paar Anreize gegeben! Statt Expression oder VAR Schllacht mit 12 + 12 + 3 Variablen o.ä. kannst du es ggf. mit Array u.a. Mehtoden sinvoller verketten.


Der Aufbau von VAR ist immer gleich. Es gelten die gleichen Regeln für das zurücksetzen und summieren wie auch in anderen Sprachen.

Gruppen + Autosummen nehmen einen das mitunter ab. Letzteres macht aber nichts anderes als wie oben beschrieben. Du kannst Auto-Summe auch von Hand einfach nachbauen.

Du musst nur im Hinterkopf haben, wann etwas "stastisch" ist - Kopf/ Fuss oder die DS durchlaufen werden. Das sind genau die Punkte für SET, RESET, SUM etc.
Member: MadMax
MadMax Nov 03, 2022 at 13:57:45 (UTC)
Goto Top
Hallo Balgor,

mach Dir Deine Abfrage für die Auswertung zurecht:
select	Filiale, VorgangID, month (min (Datum)) as Monat
from	(select Filiale, VorgangID, Datum from Auftragtabelle
	union
	select Filiale, VorgangID, Datum from Rechnungtabelle
	union
	select Filiale, VorgangID, Datum from Gutschrifttabelle
	union
	...) t
group by Filiale, VorgangID
having	min (Datum) between '01.01.2022' and '31.12.2022'  

Je nach Datenbank kannst / mußt Die Unterabfrage mit den Unions auch in eine Sicht packen.

Den Filter für das Jahr mußt Du nach der Gruppierung mittels "having" reinbringen. Wenn Du es vorher machst, hast Du sonst das Problem mit den doppelten VorgangsIDs bei den Jahren, genauso, wie Du es jetzt bei den Monaten hast.

Damit hast Du dann den ersten Monat je Filiale und VorgangsID und kannst Deine Pivottabelle basteln.

Gruß, Mad Max