Bericht Datenbank-Ansicht (Fenster ID-180)
In iDempiere kann man per Konfiguration im Application Dictionary eigene Ansichten auf seine Datentabellen definieren. Dies geschieht im Fenster Bericht_Datenbank-Ansicht_(Fenster_ID-180).
Wofür ist die Berichtsansicht nun gut? Die größte Flexibilität bietet es natürlich, in der Datenbank komplett ein Neues View für Berichte anzulegen. Die hier vorgestellte Methode der Berichtsansicht hilft jedoch in vielen Fällen, Daten für verschiedene Auswertungen enger zusammenzustellen. Dabei liegt die größte Stärke eigentlich in der Kombination beider Verfahren.
Dieser Artikel ist von Thomas Bayen. Meine Artikel sind grundsätzlich nie "fertig", sondern immer eine Einladung, sie zu verbessern. Ich lade jeden gerne jederzeit ein, Verbesserungen hier direkt einzupflegen. Wer möchte, kann mich auch gerne kontaktieren.
Welches Verfahren für welche Daten?
Um ein komfortables und flexibles System für Statistik und Berichte zu erhalten, empfehle ich, gedanklich in mehreren Schritten zu arbeiten.
1. Schritt: Tabellen
Die eigentlichen Daten liegen in iDempiere erst einmal in normalen Datentabellen. Diese sind normiert, d.h. es sind sehr viele Daten durch Referenzen miteinander verknüpft. Auf diese Art erhalten wir einerseits eine sehr übersichtliche Datenstruktur aber leider führt das auch dazu, das interessante Daten fehlen. So enthält ein Geschäftspartner zwar eine Referenz zur Geschäftspartnergruppe, aber damit hat man noch lange nicht den Namen dieser Gruppe, um ihn in Berichten auszugeben.
2. Schritt: Datenbank-View
Nun kann man mittels SQL "JOIN" Klauseln in der PostgreSQL-Datenbank Views einrichten, die Daten aus verschiedenen Tabellen zusammenführen. Ein solches View erzeugt eine flache Version der Datenbank und bildet unsere vormals strukturierten Daten auf eine einzige Tabelle ab, die dann sehr viele Spalten hat. Diese Tabelle bekommt eine eigene Tabellendefinition im Application Dictionary von iDempiere, was uns ermöglicht, auf diese Daten zuzugreifen.
3. Schritt: Eingrenzung durch Berichtsansicht
Die hier vorgestellte Funktionalität der Berichtsansicht dient nun dazu, die vorhandenen Daten einzugrenzen. In einer solchen Ansicht werden nur genau jene Spalten ausgewählt, die man in seinem Bericht wirklich benutzen möchte. Außerdem erlaubt die Berichtsansicht, die Daten mittels einer SQL-WHERE Clause einzugrenzen sowie mittels einer SQL GROUP Clause (und entsprechenden Aggregatfunktionen) zu verdichten.
Der Vorteil dieser Vorgehensweise ist, das die hier gemachten Einschränkungen direkt als SELECT-BEfehl an die Datenbank geschickt werden. So hat der Optimizer der Datenbank Gelegenheit, die Daten, die man nicht haben will, gar nicht erst zu laden und bereitzustellen. (Der PostgreSQL-Optimizer ist hier recht gut aufgestellt.) Das spart viel Zeit in der Datenbank, bei der Übertragung nach iDempiere und vor allem in der Persistenzschicht von iDempiere.
Bei der Erstellung eines Berichtes werden die hier zusammengestellten Daten in eine Berichtstabelle kopiert, die dann den angezeigten Bericht darstellt. Diese Berichtstabelle ist dann das Objekt, auf dem der Berichtsgenerator z.B. mit dem Druckformat angewendet wird.
4. Schritt: Ausgabe durch ein Druckformat (oder JasperReports)
Nun kann man im Druckformat nochmals angeben, das bestimmte Spalten gar nicht gedruckt oder gruppiert werden etc. Eine Gruppierung hier (im Gegensatz zum Berichts-View) hat den Vorteil, die Zusammenfassung der Daten flexibel ein- und ausschalten zu können und den Nachteil, das alle Daten erst bereitgestellt werden, was sehr langsam sein kann. Man tauscht also den optimierten Datenzugriff der Datenbank gegen die Flexibilität der Anzeige.
Natürlich kann ein Druckformat auch einen JasperReport benutzen. Hier gilt aber im Grunde das Gleiche. Ein ordentlich implementierter JasperReport in iDempiere wird ebenfalls die vorbereitete Berichtstabelle benutzen und damit den gleichen Gesetzmäßigkeiten wie ein interner Report unterliegen. (Wer in seinem JasperReport die Möglichkeiten des direkten SQL-Zugriffs auf alle Tabellen nutzt, mag hier Argumente für Sonderwege finden.)
Wie geht's?
Grundsätzlich kann eine Berichtsansicht bei der Anlage eines Druckformats angegeben werden. Auch eigenständige Berichts-Prozesse (die z.B. aus dem Menü heraus aufgerufen werden), erlauben die Angabe einer Berichtsansicht. Öffnet man diese (Bericht_Datenbank-Ansicht_(Fenster_ID-180)), so kann man zuerst einmal einen Namen vergeben. Diese sollte z.B. mit einem eigenen Prefix beginnen, um die eigenen Ansichten später leichter finden zu können. Auch den Entity Typ kann man entsprechend angeben (oder "User Maintained" lassen, falls man keinen eigenen verwendet). Als Tabelle sollte man nun die Basistabelle angeben, die durch diese Ansicht "abgespeckt" werden soll. Bei dieser Tabelle kann es sich natürlich sowohl um eine "echte" Tabelle als auch um ein Datenbankview handeln. Beide werden bekanntlich in iDempiere fast gleich eingerichtet.
WHERE-Klausel
Die erste - und wichtigste - Einschränkung ist nun die Angabe einer WHERE-Klausel. Hier können die angezeigten Daten zeilenweise eingeschränkt werden. An dieser Stelle können übrigens auch Umgebungs-Variablen verwendet werden, so das man z.B. nur die Kunden des aktuell eingeloggten Benutzers anzeigen kann.
Berichtszeilen
Unterhalb gibt es nun ein Detail-Register "Berichtsansichts-Zeilen". Dieses Register kann man völlig unangetastet lassen, was bedeutet, das alle Zeilen der zugrundeliegenden Tabelle für den Bericht eingelesen werden. Gibt man jedoch hier eine Zeile an, so müssen alle verwendeten Zeilen explizit angegeben werden.
Formeln
In jeder Zeile muss ich eine Formel angeben. Innerhalb dieser Formel steht der Platzhalter "@" für den Spaltenwert selbst. Möchte ich also nur die Menge der geladenen Spalten einschränken, reicht es, diesen überall einzusetzen. Ich kann hier aber auch SQL-Formeln angeben und mit einem Wert rechnen etc. Dabei muss ich (so, wie der Code in JavaEngine.java im Moment implementiert ist), genau ein '@' in der Formel verwenden, das dann durch die Spaltenbezeichnung ersetzt wird.
Leider kann man auf diese Art keine zusätzlichen Spalten (also z.B. eine Summe zweier anderer Spalten) definieren, da jeder Eintrag später über die angegebene Spalten-Definition (deren Auswahlfeld durch die zugrundeliegende Tabelle vorgegeben ist) gefunden und benutzt werden kann. Es steht einem allerdings frei, eine vorhandene, aber nicht benutzte Spalte für einen solchen Zweck "umzuwidmen".
Gruppierung
Unter Gruppierung versteht man die Zusammenfassung mehrerer Zeilen. Hier gibt es zwei Besonderheiten. Zum einen muss ich die Spalten angeben, nach denen ich gruppiere. Als Spaltenfunktion setze ich hier auch am einfachsten "@". Die Spalten, deren Werte ich nun innerhalb der Gruppe aggregieren will, erhalten eine Funktion. Hier kann man im SQL Formelfeld sogenannte Aggregatfunktionen benutzen, um z.B. eine Summe zu berechnen. Ein Beispiel ist "SUM(@)". Diese aggregierten Felder erhalten nun noch einen Haken beim Feld "Gruppierungsfunktion". Wichtig ist, das alle Felder, die Aggegatfunktionen enthalten, diesen Haken gesetzt haben und alle, die keine enthalten (also nach denen gruppiert wird), keinen.
Bei gruppierten Feldern ist übrigens darauf zu achten, das die Gruppierungsfelder später im Druckformat auch als Sortierfelder angegeben werden. Erstens würde das anders keinen Sinn machen und zweitens gibt das auch sonst eine Fehlermeldung bei der Ausgabe des Berichts.
Beispiel
Als Beispiel möchte ich z.B. aus den Buchhaltungsdaten die Umsätze eines Kunden zusammenfassen:
- Als Basistabelle nehme ich "RV_Fact_Acct". Das ist ein View, das die Tabelle der Buchführungs-Details mit einigen anderen (von dort referenzierten) Tabellen kombiniert.
- Mittels des WHERE-Feldes begrenze ich die Daten auf die Zeilen, die auf mein Verbindlichkeiten-Konto buchen (dazu vergleiche ich mit der Kontonummer in "accountvalue").
- Ich erzeuge zwei Zeilen für die Kundennummer und den Kundennamen (beide sind Spalten in RV_Fact_Acct) und lasse den Haken für die Gruppierungsfunktion ausgeschaltet. Als Formel setze ich jeweils "@".
- Dann erzeuge ich eine dritte Spalte mit der Formel "SUM(@)". Dort setze ich den Haken für eine Gruppierungsfunktion.
Das war's schon. Jetzt muss ich noch bei der Anzeige im Druckformat darauf achten, das ich die richtigen drei Spalten benutze ich nach den ersten beiden sortiere.
Fenster
Fenster: Bericht Datenbank-Ansicht
Beschreibung: Verwaltung Datenbank-Ansichten für Berichte
Hilfe: Im Fenster "Bericht Datenbank-Ansicht" legen Sie die SQL-Abfragen zur Erzeugung von Berichten fest. Dieses Fenster ist nur für die Systemadministration bestimmt.
TAB: Bericht Datenbank-Ansicht
Beschreibung: Bericht Datenbank-Ansicht festlegen
Hilfe Unter "Bericht Datenbank-Ansicht" legen Sie die SQL-Abfrage zur Erzeugung von Berichten fest.
Folgende Felder werden in der Standardmaske angezeigt:
Original Name (englisch) | Name (deutsch) | Beschreibung | Hilfe | Technische Daten |
---|---|---|---|---|
Report View | Bericht Datenbank-Ansicht | Datenbank-Abfrage, die zur Erzeugung dieses Berichts verwendet wird. | Die "Datenbank-Ansicht" kennzeichnet die SQL-Abfrage, die zur Erzeugung des Berichts verwendet wird. | AD_ReportView_ID numeric(10) NOT NULL ID |
Client | Mandant | Mandant für diese Installation | Ein "Mandant" ist eine Firma oder eine juristische Person. Mandanten können keine Daten teilen/nicht gemeinsam auf Daten zugreifen. | AD_Client_ID numeric(10) NOT NULL Table Direct |
Organization | Organisation | Organisatorische Einheit innerhalb des Mandanten | Eine "Organisation" ist die Geschäftseinheit eines Mandanten oder eine juristische Person, z.B. ein Geschäft oder eine Abteilung. Organisationen können gemeinsam auf Daten zugreifen, bzw. die Daten gemeinsam verwenden. | AD_Org_ID numeric(10) NOT NULL Table Direct |
Name | Name | Alphanumerischer Identifikator des Eintrags | Der "Name" eines Eintrags wird zusätzlich zum Suchschlüssel als Standardsuchoption verwendet. Ein Name kann bis zu 60 Zeichen lang sein. | Name character varying(60) NOT NULL String |
Description | Beschreibung | Optionale Kurzbeschreibung des Datensatzes | Eine Beschreibung ist auf 255 Zeichen begrenzt. | Description character varying(255) String |
Active | Aktiv | Der Datensatz ist im System aktiv | Es gibt zwei Methoden um Datensätze im System zu sperren: Eine Methode ist den Datensatz zu löschen. die andere ist es den Datensatz zu deaktivieren. Ein deaktivierter Datensatz kann nicht mehr ausgewählt werden, steht aber weiterhin in Berichten zur Verfügung. Es gibt zwei Gründe dafür einen Datensatz zu deaktivieren und nicht zu löschen: (1) Das System benötigt den Datensatz für Audits (2) Der Datensatz wird von anderen Datensätzen referenziert. Es ist z.B. nicht möglich einen Geschäftspartner zu löschen, wenn zu diesen Geschäftspartner Rechnungen vorliegen. In diesem Fall wird der Geschäftspartner deaktiviert und kann nicht mehr für zukünftige Vorgänge verwendet werden. | IsActive character(1) NOT NULL Yes-No |
Entity Type | Entitätstyp | Entitätstyp im Dictionary. Legt Besitz und Synchronisation fest. | Die Entitätstypen "Dictionary", "ADempiere", "iDempiere" und "Application" könnten automatisch synchronisiert und Anpassungen gelöscht oder überschrieben werden. Für Anpassungen die Entität kopieren und "Benutzerverwaltet" auswählen! | EntityType character varying(40) NOT NULL Table |
Table | Tabelle | Tabelle für die Felder | Die Datenbanktabelle liefert die Informationen der Tabellendefinition | AD_Table_ID numeric(10) NOT NULL Table Direct |
Sql WHERE | SQL WHERE | Voll qualifizierter SQL WHERE-Ausdruck | "SQL WHERE" zeigt den SQL WHERE-Ausdruck an, der für die Wahl des Eintrags verwendet wird. Der Where-Ausdruck wird einer Suchanfrage hinzugefügt. Voll qualifiziert bedeutet "Tabellenname.Spaltenname". | WhereClause character varying(2000) String |
Sql ORDER BY | SQL ORDER BY | Voll qualifizierter ORDER BY-Ausdruck | Der "ORDER BY-Ausdruck" zeigt den SQL ORDER BY-Ausdruck an, der für die Datenselektion verwendet wird | OrderByClause character varying(2000) String |
TAB: Ansicht Berichtspalte
Beschreibung: Ansicht Berichtspalte
Hilfe Im Register "Ansicht Berichtspalte" legen Sie die Spalten fest, die bei der Erstellung von Select SQL aufgehoben werden.
Folgende Felder werden in der Standardmaske angezeigt:
Original Name (englisch) | Name (deutsch) | Beschreibung | Hilfe | Technische Daten |
---|---|---|---|---|
Report view Column | Für den Bericht siehe Spalte | null | null | AD_ReportView_Col_ID numeric(10) NOT NULL ID |
Client | Mandant | Mandant für diese Installation | Ein "Mandant" ist eine Firma oder eine juristische Person. Mandanten können keine Daten teilen/nicht gemeinsam auf Daten zugreifen. | AD_Client_ID numeric(10) NOT NULL Table Direct |
Organization | Organisation | Organisatorische Einheit innerhalb des Mandanten | Eine "Organisation" ist die Geschäftseinheit eines Mandanten oder eine juristische Person, z.B. ein Geschäft oder eine Abteilung. Organisationen können gemeinsam auf Daten zugreifen, bzw. die Daten gemeinsam verwenden. | AD_Org_ID numeric(10) NOT NULL Table Direct |
Report View | Bericht Datenbank-Ansicht | Datenbank-Abfrage, die zur Erzeugung dieses Berichts verwendet wird. | Die "Datenbank-Ansicht" kennzeichnet die SQL-Abfrage, die zur Erzeugung des Berichts verwendet wird. | AD_ReportView_ID numeric(10) NOT NULL Table Direct |
Column | Spalte | Spalte in der Tabelle | Verbindung zur Spalte einer Tabelle | AD_Column_ID numeric(10) Table Direct |
Active | Aktiv | Der Datensatz ist im System aktiv | Es gibt zwei Methoden um Datensätze im System zu sperren: Eine Methode ist den Datensatz zu löschen. die andere ist es den Datensatz zu deaktivieren. Ein deaktivierter Datensatz kann nicht mehr ausgewählt werden, steht aber weiterhin in Berichten zur Verfügung. Es gibt zwei Gründe dafür einen Datensatz zu deaktivieren und nicht zu löschen: (1) Das System benötigt den Datensatz für Audits (2) Der Datensatz wird von anderen Datensätzen referenziert. Es ist z.B. nicht möglich einen Geschäftspartner zu löschen, wenn zu diesen Geschäftspartner Rechnungen vorliegen. In diesem Fall wird der Geschäftspartner deaktiviert und kann nicht mehr für zukünftige Vorgänge verwendet werden. | IsActive character(1) NOT NULL Yes-No |
Function Column | Funktion Spalte | Spalte mit Funktion überschreiben. | "Funktion in Spalte" zeigt an, dass eine Spalte mit einer Funktion überschrieben wird. | FunctionColumn character varying(60) NOT NULL String |
SQL Group Function | SQL Gruppierungsfunktion | Die Funktion erzeugt einen Group by-Ausdruck | Das Optionsfeld "SQL-Gruppierungsfunktion" zeigt an, ob eine Funktion einen Group by-Ausdruck im letztendlichen SQL erzeugt. | IsGroupFunction character(1) NOT NULL Yes-No |