Aggregation

Projektion - Kurzfassung

Zweck: Ermöglicht einfache Berechnungen für einzelne Feldwerte und Aggregationen für Listen von Feldwerten, die optional per Gruppierung als Teilmengen aus einer durch die Suche definierten Grundmenge gebildet werden können.

images/download/attachments/157877408/image-2023-11-14_7-54-14-version-1-modificationdate-1699944860768-api-v2.png

Der Projektionstyp Aggregation ermöglicht verschiedene einfache Berechnungen (für einzelne Feldwerte) und Aggregationen für Listen von Feldwerten, die optional per Gruppierung als Teilmengen aus einer durch die Suche definierten Grundmenge gebildet werden können.

Die folgende Tabelle teilt die Optionen für den Typ der Berechnung/Aggregation in Kategorien ein und gibt je Typ an, welcher Datentyp jeweils per Projektion unterstützt wird.

  • Nur die hier als Aggregationsfunktionen zusammengefassten Typen können mehrere Rückgabewerte aus der Projektion verarbeiten und berücksichtigen dabei ggf. Teilmengen aus einer Gruppierung im Kontext der Suche.

  • Die anderen Berechnungsfunktionen ermöglichen einfache Berechnungen bzw. "Umwandlungen" von Einzelwerten eines bestimmten Datentyps aus der Projektion.

Typ

Funktionsname

Datentyp für
die Projektion

Beschreibung

Aggregationsfunktionen

Anzahl

COUNT

beliebig

Anzahl der zu aggregierenden Einzelwerte, die nicht "Kein Wert" ($null) sind.

Anzahl (unterschiedlich)

COUNT_DISTINCT

Anzahl der unterschiedlichen Einzelwerte, die nicht "Kein Wert" ($null) sind.

Min

MIN

Minimalwert (nach der Sortierlogik der verwendeten Datenbank für den Datentyp)

Max

MAX

Maximalwert (nach der Sortierlogik der verwendeten Datenbank für den Datentyp)

Wenigste

LEAST

Minimalwert (nach der Sortierlogik der verwendeten Datenbank für den Datentyp)

Summe

SUM

numerisch

Summe der zu aggregierenden Einzelwerte

Durchschnitt

AVG

Arithmetisches Mittel der zu aggregierenden Einzelwerte, die nicht "Kein Wert" ($null) sind.
(=Summe/Anzahl)

Arithmetik (für einzelnen Zahlenwert)

Absolut

ABS

numerisch

Gibt den Absolutbetrag eines Zahlenwerts zurück
("entfernt" ein negatives Vorzeichen, sofern vorhanden)

Negieren

NEG

Wechselt das Vorzeichen eines Zahlenwerts (+|-)

Wurzel

SQRT

Quadratwurzel eines Zahlenwerts

Logik (für einzelnen Booleschen Wert)

Nicht

NOT

Boolean

Kehrt einen Wahrheitswert um (true|false)

Textverarbeitung (für einzelnen Textwert)

Länge

LENGTH

String

Länge einer Zeichenfolge (Long-Wert) oder $null

Klein

LOWER

Gibt eine Zeichenfolge in Kleinbuchstaben wieder

Groß

UPPER

Gibt eine Zeichenfolge in Großbuchstaben wieder

Trim

TRIM

"Trimmt" (=entfernt) randständige Leerzeichen von einer Zeichenfolge

Konfiguration

Parameter

Typ

Beschreibung

Name

String

Der optionale Parameter Name kann verwendet werden, um der Projektion einen (Alias-)Namen zuzuweisen.

  • Wenn kein Name angegeben ist, wird als Spaltenname (sofern relevant) der im Kontext der Projektion anwendbare Name nach dem Schema "<function> of <projection>" versehen. Den Platzhalter <function> ersetzt dabei der englische "Funktionsname" aus der obigen Tabelle für den ausgewählten Typ.

Typ

AggregateType

images/download/attachments/157877408/image-2023-11-15_9-0-29-version-1-modificationdate-1700035230241-api-v2.png

Der Typ bestimmt welche Art von Aggregation, Berechnung under Umwandlung auf Basis der Projektion vorgenommen werden soll.

  • Das Auswahlfeld/Combobox-Element mit Suchfunktion bezieht sich auf die statische Aufzählung "Suche Aggregatstyp" (AggregateType).

HINWEIS◄ Die Gliederung der obigen Tabelle nach Kategorien ("Aggregationsfunktionen", "Arithmetik", ...) spiegelt sich nicht im Dropdown.

Projektion

Projektion

Für den Parameter Projektion können grundsätzlich beliebige Projektionen konfiguriert werden, solange diese einen für den Typ zulässigen Datentyp als Rückgabewert liefern und das verwendete Datenbanksystem deren Verwendung im gegebenen Kontext unterstützt.

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg ACHTUNGimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg Für "echte Aggregationen", also solche mit einem Typ aus der Kategorie Aggregationsfunktionen, sind ggf. folgende Einschränkungen relevant:

  • Eine Aggregationsfunktion kann generell nicht innerhalb einer anderen Aggregation verwendet werden, die ebenfalls eine Aggregationsfunktion ist. Man kann Aggregationsfunktionen nicht verschachtelt einsetzen.

  • Bestimmte Datenbanksysteme (z. B. MSSQL) unterstützen außerdem die Verwendung einer Subselect Projektion im Kontext einer Aggregationsfunktion nicht.

Beispiele für die Umwandlung von Einzelwerten

Arithmetik - Absolut (ABS): Absolutbetrag eines numerischen Felds als Restriktionsprojektion

Das Standardfeld "Zuletzt geändert von" (lastModifierId) für Entitäten beinhaltet in der Regel einen positiven Long-Wert, der der "ID" (id) eines Benutzerkontos (s. Benutzer) entspricht.

Falls allerdings die letzte Änderung an einer Entität im Kontext eines Gastbenutzerkontos (s. Gastbenutzer) vorgenommen wurde, wird dessen "ID" (id) als negativer Wert im lastModifierId-Feld eintragen, um eine Unterscheidung von Benutzern mit derselben ID sicherzustellen.

Im Datengrid einer Übersicht erscheint die "Zuletzt geändert von" Spalte per Standard leer, wenn dieses Feld ein Gastbenutzerkonto referenziert, weil das per Standard als Spaltenprojektion implementierte Nachschlagen des Benutzernamens (s. Subselect Projektion) für negative Referenzen "unproduktiv" ist.

Ohne Rücksicht auf die Anzeige soll die Filterfunktion für diese Spalte so angepasst werden, dass man Filterkriterien für den positiven Long-Wert einer Konto-ID eingeben kann, die greifen egal, ob es sich um Benutzer oder Gastbenutzer handelt.

Konfiguration:

images/download/attachments/157877408/image-2023-11-17_16-17-51-version-1-modificationdate-1700234272148-api-v2.png

In den Datengrid-Einstellungen für die betreffende Übersicht müssen die Einstellungen für die Spalte "Zuletzt geändert von" (lastModifierId) eingeblendet werden.

Für diese Spalte liegt im Reiter für die Definition der Restriktionsprojektion per Standard keine Konfiguration für eine Projektion vor. Damit gilt die Projektion per Standard auch als Restriktionsprojektion.

Wenn man eine Restriktionsprojektion wie rechts abgebildet konfiguriert, übersteuert diese das Standardverhalten wie folgt:

  • Anstelle des auf Benutzer zugeschnittenen Textwerts (Schema: {id} - {username}) greift für den Filter als Vergleichswert eine Aggregation mit Typ "Absolut" (ABS), die hier dazu dient, den aus der Feldprojektion für das lastModifierId-Feld gelesenen Long-Wert vom ggf. vorhandenen Minuszeichen (für Gastbenutzer) zu befreien.

  • Die positiven ID-Werte für Benutzer gibt die Aggregation mit Typ "Absolut" (ABS) unverändert zurück.

  • Die Charakteristik des Filters passt sich dem numerischen Datentyp an.

ANMERKUNG◄ Natürlich ist es nicht optimal, dass diese Restriktionsprojektion ein Benutzerkonto und ein Gastbenutzerkonto mit derselben ID nicht voneinander unterscheiden kann. Soweit Überschneidungen der verwendeten IDs überhaupt praxisrelevant sind, bleibt allerdings immer noch die Möglichkeit, die Projektion so anzupassen, dass Benutzer und Gastbenutzer trotzdem deutlich voneinander unterschieden werden können.

Laufzeitbeispiel:

images/download/attachments/157877408/image-2023-11-20_18-37-3-version-1-modificationdate-1700501830234-api-v2.png

Der Screenshot links zeigt einen Ausschnitt aus der Spalte "Zuletzt geändert von", für die nicht nur die Restriktionsprojektion (wie oben) angepasst wurde, sondern auch die Projektion, so dass für Gastbenutzer die (positive) ID des Kontos mit dem Präfix "G#" erscheint.

Wie der Filterausdruck (7251|2701) verdeutlicht, bezieht sich der Filter trotzdem wie gewünscht ausschließlich auf die positiven ID-Werte der betreffenden Konten.

ANMERKUNG◄ Die Projektion verwendet eine Wenn ( Case ) Projektion (s. Screenshot unten), die den Anzeigetext für Referenzen auf Gastbenutzer im rechten Zweig der Fallunterscheidung durch eine einfache Textverkettungsprojektion zusammenstellt. Dabei kommt wiederum eine Aggregation mit dem Typ "Absolut" (ABS) zum Einsatz, um das Minuszeichen des negativen lastModifierId-Werts zu eliminieren. Dem linken Zweig der Fallunterscheidung wurde die per Standard vorgegebene Subselect Projektion platziert, die den Benutzernamen im Konto nachschlägt.


images/download/attachments/157877408/image-2023-11-17_17-18-31-version-1-modificationdate-1700237911979-api-v2.png

Arithmetik - Negieren (NEG): Negieren von Zahlenwerten (Vorzeichenumkehr)

Die Positionen eines benutzerdefinierten Entitätstyps "Konto" (s. Eigene Typdefinitionen) dienen zur Erfassung von Ein- und Auszahlungen, die unabhängig von ihrem Typ immer als positive Zahlenwerte in einem Feld "Zahlbetrag" (payment.value) gepflegt werden. Ein zugehöriges Textfeld "Zahlungstyp" (paymentType) dient der weiteren Klassifizierung des Vorgangs.

Per Konvention sollen Auszahlungen über Schlüsselwerte für den "Zahlungstyp" (paymentType) gekennzeichnet werden, die mit dem Buchstaben "R" beginnen.

Über eine Tupel-Suche, die direkt die Positionsebene (AccountLineItem) adressiert, sollen die Salden für jede "Konto"-Instanz so berechnet werden, dass die Summe aller Auszahlungen von der Summer aller Einzahlungen abgezogen wird.

Konfiguration:

Die Tupel-Suche verwendet die zwei rechts abgebildeten Projektionen:

  • Die erste, eine Feldprojektion identifiziert die übergeordnete Entität (das betreffende "Konto") anhand des Referenzfelds parentId.
    WICHTIG◄ Dieses Feld muss auch im Kontext der Gruppierung projiziert werden, damit alle Positionen je "Konto" aggregiert werden.

  • Als zweite Projektion wird eine Aggregation mit dem Typ "Summe" (SUM) verwendet, die per Name TOTAL den aggregierten Saldo je "Konto" berechnen soll.

  • Damit die je Position hinterlegten positiven Zahlbeträge im Kontext der Aggregation abhängig vom angegebenen "Zahlungstyp" korrekt gegeneinander verrechnet werden, muss innerhalb der Projektion eine Vorzeichenumkehr für den Betrag im Feld payment.value vorgenommen werden, wenn der "Zahlungstyp" (paymentType) mit dem Kennbuchstaben "R" beginnt:

ANMERKUNG◄ Das Beispiel verwendet die Berechnungsfunktion NEG hier eher zufällig im Kontext einer "echten" Aggregationsfunktion (SUM). Berechnungsfunktionen können jederzeit auch ohne Aggregationsfunktion und Gruppierung eingesetzt werden, etwa auch um Werte in Bedingungen "anzupassen".

images/download/attachments/157877408/image-2023-11-17_15-27-28-version-1-modificationdate-1700231249550-api-v2.png

Arithmetik - Wurzel (SQRT): Quadratwurzel

Eine Tupel-Suche für Sendungen soll neben anderen Kennzahlen einen Hinweis auf die Komplexität einer Sendung in einer Spalte COMPLEXITY die Quadratwurzel aus der Anzahl der unterschiedlichen Werte für die "Übergeordnete Position" angeben.

Konfiguration:

Die rechts dargestellte Projektion liefert in Verbindung mit einer - hier nicht gezeigten - Gruppierung der Suche nach dem Feld "ID" (id) der Sendung die gewünschte Kennzahl für die "Komplexität":

  • Die innere Aggregation mit dem Typ "Anzahl (unterschiedlich)" ermittelt unter Berücksichtigung der Gruppierung die "Vielfalt" der Werte für das Feld "Übergeord. Positions-Nr." (parentLineItemId) der "Positionen" (lineItems) je Sendung.

  • Die äußere Aggregation mit dem Typ "Wurzel" (SQRT) berechnet aus dem aggregierten Zahlenwert aus der inneren Aggregation den "radizierten" Wert.

images/download/attachments/157877408/image-2023-11-20_17-35-28-version-1-modificationdate-1700498134917-api-v2.png

Laufzeitbeispiel:

ID,VOLUME,COMPLEXITY
8455,1,2.0
7955,10,1.7320508075688772
7951,,1.7320508075688772
4006,2,1.7320508075688772
9251,4,1.4142135623730951
9252,4,1.0

Die Beispieldaten links zeigen für die Spalte COMPLEXITY die berechneten Double-Werte für "Komplexitätswerte" von √4, √3, √2 und √1.

Die Quadratwurzel kommt hier zum Einsatz, da eine Verdopplung der Anzahl von "Übergeordneten Positionen" in der Positionshierarchie nicht doppelte Komplexität bedeuten soll. Eine Vervierfachung aber schon.

Logik - Nicht (NOT): Logische Verneinung

In einer Tupel-Suche für Benutzer soll das Boolesche Feld "Aktiv" logisch umgekehrt werden, so dass mit der Spaltenbeschriftung wie DEACTIVATED für die Benutzer der Wert $true erscheint, für die das "Aktiv"-Feld den Wert $false enthält und umgekehrt.

Konfiguration:

Die rechts abgebildete Aggregation definiert per Name die Ausgabespalte DEACTIVATED:

  • Der Typ "Nicht" (NOT) erwartet einen Booleschen Wert für die Projektion, der logisch verneint wird.

  • Die Projektion verwendet eine Feldprojektion, die auf das Feld "Aktiv" (active) zugreift.

images/download/attachments/157877408/image-2023-11-17_17-40-19-version-1-modificationdate-1700239220566-api-v2.png

HINWEISE

  • Das Feld "Aktiv" für Benutzer ist per Definition "nicht nullable", so dass der Rückgabewert der Aggregation in allen Fällen $true oder $false lauten wird.

  • Falls für den Rückgabewert der Projektion neben $true und $false auch $null ergeben kann, liefert die Aggregation mit dem Typ "Nicht" (NOT) den Rückgabewert $null, wenn der Originalwert $null ist.

Textverarbeitung – Länge (LENGTH): Textlänge als Filterbedingung

Im der Adressfeld "Kontonummer" (address.accNumber) für Firmen wird per Konvention eine neunstellige Zeichenfolge erwartet.

Eine Suche soll eine Liste aller Firmen liefern, für die diese Konvention für das Adressfeld "Kontonummer" nicht erfüllt ist.

Konfiguration:

images/download/attachments/157877408/image-2023-11-20_7-28-0-version-1-modificationdate-1700461685317-api-v2.png

Innerhalb einer ODER-Verknüpfung müssen zwei Instanzen der Feld Einschränkung verwendet werden, um Firmen zu identifizieren, für die das Adressfeld "Kontonummer" (address.accNumber) entweder unapssend oder überhaupt nicht ausgefüllt ist:

  • Die linke Feld Einschränkung wertet als Prüfwert das Textfeld "Kontonummer" per Aggregation mit dem Typ "Länge" aus, um zu prüfen, ob die Länge einer vorhandenen Zeichenfolge vom Normwert 9 abweicht (!=).

  • Die rechte Feld Einschränkung ist erforderlich, um den Fall abzudecken, dass überhaupt keine Angabe für die "Kontonummer" vorliegt.

WICHTIG◄ Die rechte Feld Einschränkung prüft formal, ob die "Kontonummer" einen Leerstring ("") enthält. Tatsächlich wird diese Bedingung datenbankseitig so umgesetzt, dass sie prüft, ob ein Leerstring oder "Kein Wert" ($null) vorliegt.

  • Die Aggregation mit Typ "Länge" liefert nur in dem Sonderfall den Wert 0, dass das Adressfeld "Kontonummer" tatsächlich einen Leerstring ("") und nicht "Kein Wert" ($null) enthält.

Textverarbeitung – Groß (UPPER): Benutzer nach dem Anfangsbuchstaben im Benutzernamen gruppieren

Eine CSV-Suche soll die Anzahl der Benutzer ausgeben, die sich denselben Anfangsbuchstaben für den "Benutzername" (username) teilen.

Dabei soll nicht zwischen Groß- und Kleinschreibung unterscheiden werden (z. B. {admin,AEINSTEIN}A).

Konfiguration:

Als Basis für den Einsatz einer Aggregation mit dem Typ "Anzahl" (s. unten) für die eigentlichen Aggregation der Benutzerkonten wird eine Gruppierung benötigt, die wie rechts abgebildet konfiguriert werden kann:

  • Innerhalb einer Aggregation definiert der Typ "Groß" (UPPER), dass der Rückgabewert der Projektion in Großbuchstaben umgewandelt werden soll.

  • Als Projektion dient hier eine Teilstring Projektion, die das erste Zeichen aus dem Feld "Benutzername" (username) zurückgibt.


images/download/attachments/157877408/image-2023-11-20_10-18-51-version-1-modificationdate-1700471936464-api-v2.png


Als Projektionen für die CSV-Suche sollen die folgenden beiden Spalten ausgegeben werden:

  • Als erste Spalte soll der Großbuchstabe ausgegeben werden, nach dem die Benutzer zwecks Zählung gruppiert werden:

    • Die in der Gruppierung (s. o.) verwendete Projektion muss aus formalen Gründen im Kontext einer echten Aggregationsfunktion verwendet werden. Für die äußere Aggregation wurde hier der Typ "Min" ausgewählt. Die zugehörige Projektion kann mit dieser Einstellung direkt aus der Gruppierung übernommen werden.

  • Die zweite Spalte definiert den Zahlenwert für die Anzahl der Benutzer, die sich den in der ersten Spalte angegebenen Anfangsbuchstaben im Feld "Benutzername" teilen durch eine weitere Aggregation:

    • Als Typ ist hier "Anzahl" (COUNT) ausgewählt.

    • Die Projektion bezieht sich auf das Feld "ID" (id), also die eindeutige Kennung des Benutzerkontos, das zuverlässig für jeden Benutzer eine Wert enthält.


images/download/attachments/157877408/image-2023-11-20_10-34-0-version-1-modificationdate-1700472845166-api-v2.png


Textverarbeitung – Klein (LOWER): Groß-/Klein-unspezifischer Vergleich

Eine Suche soll alle Benutzer auflisten, für die eine Übereinstimmung zwischen dem Adressfeld "Land" (address.countryCode) mit den ersten beiden Zeichen der internen Kennung für die "Sprache" (locale) übereinstimmt.

Konfiguration:

Die rechts abgebildete Feld Einschränkung ergibt den gewünschten Abgleich:

  • Als Prüfwert (links) dient eine Teilstring Projektion, die die ersten beiden Zeichen der internen Kennung für die "Sprache" (locale) des Benutzers zurückgibt. Diese sollten per Konvention (s. Sprache) Kleinbuchstaben sein.

  • Als Vergleichswert (rechts) wandelt eine Aggregation mit dem Typ "Klein" (LOWER) den Rückgabewert aus dem Adressfeld "Land" (address.countryCode) in Kleinbuchstaben um. Per Konvention (s. Land) handelt es sich dabei in Anlehnung an den ISO 3166 Standard um eine Kombination von zwei Großbuchstaben.

images/download/attachments/157877408/image-2023-11-20_11-8-44-version-1-modificationdate-1700474929981-api-v2.png

WICHTIG◄ Eine Aggregation mit dem Typ "Klein" kann im Allgemeinen nicht verwendet werden, um den internen Namen von Aufzählungswerten (hier: Land, Sprache) zu verarbeiten. Das klappt hier nur ausnahmsweise, da die betreffenden Felder für das Benutzerkonto (locale) bzw. die Adresse (countryCode) abweichend vom allgemeinen Standard datenbankseitig als Textfelder behandelt werden. Im Allgemeinen beinhalten Felder, die sich auf Dynamische Aufzählungen beziehen, datenbankseitig den "Ordinal"-Wert vom Typ Long. Eine Projektion auf ein solches Feld - z. B. das Adressfeld "Anrede" (address.salutation) für einen Benutzer, das sich auf die Dynamische Aufzählung Anrede bezieht - eignet sich dann nicht als Eingabewert für eine Berechnungsfunktionen zur Textverarbeitung in einer Aggregation. Beim Ausführen der Abfrage tritt in der Regel eine Fehlermeldung auf, die auf den Typkonflikt verweist.

Textverarbeitung – Trim (TRIM): Suche nach "ungetrimmten" Texten

Eine Suche soll Adressen ermitteln, für die als "Name" (name1) "ungetrimmter" Text - also eine Zeichenfolge mit mindestens einem randständigen Leerzeichen - eingegeben wurde.

Konfiguration:

Die rechts abgebildete Bedingung prüft über eine Feld Einschränkung, ob sich der als "Name" (name1) angegebene Text vom Rückgabewert der Trim-Funktion für dasselbe Feld unterscheidet (!=):

  • Als Prüfwert (links) wird direkt über eine Feldprojektion direkt auf das Feld "Name" (name1) zugegriffen.

  • Als Vergleichswert wird dieselbe Feldprojektion als Projektion innerhalb einer Aggregation mit dem Typ "Trim" (TRIM) eingesetzt.

HINWEIS◄ Eine Suche mit dieser Bedingung liefert alle Adressen zurück, auf die im Ausführungskontext Zugriff besteht, weil Adressbucheinträge auf sie verweisen. Adressen, die im Kontext anderer Entitäten (z. B. Firmen oder Benutzer) erstellt wurden, sind dagegen nicht Bestandteil des Suchergebnisses, solange der Zugriff nicht über Joins, eine Sub-Suche, o. ä. erfolgt.

images/download/attachments/157877408/image-2023-11-20_11-42-33-version-1-modificationdate-1700476958894-api-v2.png

Beispiele für Aggregationsfunktionen

Typisches Beispiel: Aggregation von Kennzahlen in einer Suche mit Gruppierung

Eine Tupel-Suche soll drei "statische Kennzahlen" zur Nutzung von Gastbenutzer-Konten durch unterschiedliche Firmen (Spalte: COMPANY) ermitteln:

  • Anzahl der Gastbenutzer je Firma (Spalte: GUEST_ACCOUNTS)

  • Summe der durch Gastbenutzer ausgeführten Logins je Firma (Spalte: GUEST_LOGINS)

  • Durchschnittliche der Anzahl der je Konto ausgeführten Logins je Firma (Spalte: LOGIN_AVG)

Laufzeitbeispiel:

Das Beispiel rechts zeigt das Ergebnis einer Tupel-Suche mit folgender Charakteristik:

  • Es liegen 3 Ergebniszeilen (row) vor, von denen jede die Daten für eine bestimmte Firma wiedergibt.

  • Der Wert (item) für die erste Spalte (COMPANY) identifiziert die Firma über deren "ID" (id).

  • Die zweite Spalte (GUEST_ACCOUNTS) gibt die Anzahl aller je Firma angelegten Gastbenutzer als Ganzzahl (long) aus.

  • Die dritte Spalte (GUEST_LOGINS) gibt die Summe der ausgeführten Logins je Firma als Ganzzahl (int) aus.

  • Die vierte Spalte (LOGIN_AVG) gibt die durchschnittliche Anzahl von Logins je Konto als Kommazahl (double) aus.
    ANMERKUNG◄ Der aggregierte Durchschnittswert kann im gegebenen Szenarion durch eine Division der Aggregationsergebnisse in Spalte 3 und 2 (GUEST_LOGINS/GUEST_ACCOUNTS) zur Verifikation "nachgerechnet" werden.

   <core:TupleSearchResult maxResults="100" count="3">
<columns>
<name>COMPANY</name>
<name>GUEST_ACCOUNTS</name>
<name>GUEST_LOGINS</name>
<name>LOGIN_AVG</name>
</columns>
<result>
<row>
<item xsi:type="xsd:long">101</item>
<item xsi:type="xsd:long">2</item>
<item xsi:type="xsd:int">0</item>
<item xsi:type="xsd:double">0.0</item>
</row>
<row>
<item xsi:type="xsd:long">1902</item>
<item xsi:type="xsd:long">12</item>
<item xsi:type="xsd:int">179</item>
<item xsi:type="xsd:double">14.916666666666666</item>
</row>
<row>
<item xsi:type="xsd:long">2202</item>
<item xsi:type="xsd:long">2</item>
<item xsi:type="xsd:int">9</item>
<item xsi:type="xsd:double">4.5</item>
</row>
</result>

Konfiguration:

Dei Datenstruktur für Gastbenutzer stellt folgende Merkmale für unsere Statistik bereit:

  • Das Feld "Firma" (companyId) ist ein Pflichtfeld für das Gastbenutzer-Konto, das mit einer Referenz auf die "ID" (id) genau eines Firmenkontos (s. Firmen) gefüllt sein muss.

  • Das Feld "Anzahl Logins" (loginCount) stellt die Anzahl der mit einem Gastbenutzer-Konto ausgeführten Logins als Ganzzahl bereit.

Da unsere Suche Kennzahlen für Gastbenutzer je Firma aggregieren soll, muss für die Suche eine Gruppierung definiert sein:

  • Der Screenshot zeigt (rechts oben) eine Feldprojektion auf das Feld "Firma" (companyId), die zu diesem Zweck eingerichtet wird.

  • Wie der Screenshot (rechts unten) zeigt, soll dieselbe Feldprojektion auch im Kontext der Sortierung als Projektion genutzt.

    ANMERKUNG◄ Es ist nicht notwendig eine Sortierung zu definieren. Sortierkriterien sollten nur dann definiert werden, wenn die Sortierung für den Einsatzzweck einen Mehrwert darstellt. Anstelle von Projektionen aus der Gruppierung könnte man innerhalb der Sortierung auch auf Aggregationsergebnisse zugreifen und im gegebenen Beispiel z. B. die Firmen absteigend nach der Anzahl der Gastbenutzer sortieren.

images/download/attachments/157877408/image-2023-11-15_11-43-58-version-1-modificationdate-1700045039130-api-v2.png

Das Screenshot rechts zeigt eine Übersicht über die für die Tupel-Suche eingerichteten Projektionen, die die Ausgabespalten definieren:

  • Die erste Spalte (COMPANY) verwendet die auch als Gruppierung angegebene Feldprojektion auf das Feld "Firma" (companyId).

  • Die Konfiguration für die nachfolgenden "Statistikspalten" wird unten Schritt für Schritt erörtert.

images/download/attachments/157877408/image-2023-11-15_11-56-35-version-1-modificationdate-1700045796403-api-v2.png

Die Spalte GUEST_ACCOUNTS verwendet eine Aggregation mit dem Typ "Anzahl" (COUNT) mit einer Feldprojektion für das Feld "ID" (id) der zu aggregierenden Gastbenutzer.

Für den Aggregationstyp "Anzahl" ist die Feldauswahl unerheblich solange sichergestellt ist, dass es nicht "Kein Wert" ($null) enthalten kann bzw. enthält. Sonst werden Gastbenutzer nicht gezählt, für das das Feld in der Projektion keinen Wert enthält.

Ohne einen Eintrag für den Parameter Name würde der Titel der Ausgabespalte "COUNT of id" lauten.

images/download/attachments/157877408/image-2023-11-15_12-11-2-version-1-modificationdate-1700046663545-api-v2.png

Die Spalte GUEST_LOGINS verwendet eine Aggregation mit dem Typ "Summe" (SUM) mit einer Feldprojektion für das Feld "Anzahl Logins" (loginCount) der zu aggregierenden Gastbenutzer.

Der Aggregationstyp "Summe" addiert alle gefundenen Zahlenwerte. Ob das Feld in der Projektion für alle aggregierten Gastbenutzer gefüllt ist, spielt für den als "Summe" zurückgegebenen Wert keine Rolle.

Ohne einen Eintrag für den Parameter Name würde der Titel der Ausgabespalte "SUM of loginCount" lauten.

images/download/attachments/157877408/image-2023-11-15_12-5-49-version-1-modificationdate-1700046349783-api-v2.png

Die Spalte LOGIN_AVG verwendet eine Aggregation mit dem Typ "Durchschnitt" (AVG) mit einer Feldprojektion für das Feld "Anzahl Logins" (loginCount) der zu aggregierenden Gastbenutzer.

Der Aggregationstyp "Durchschnitt" bezieht die Summe aller Werte aus der Projektion auf die Anzahl der aggregierten Einzelwerte, die nicht "Kein Wert" ($null) sind. Da das loginCount-Feld mit dem Wert 0 initialisiert wird und datenbankseitig keinen $null-Wert enthalten kann, ist die Interpretation des Mittelwerts im Kontext unkritisch.

Ohne einen Eintrag für den Parameter Name würde der Titel der Ausgabespalte "AVG of loginCount" lauten.

images/download/attachments/157877408/image-2023-11-15_12-12-39-version-1-modificationdate-1700046760556-api-v2.png

Ungewöhnliches Beispiel: Kennzahlen zu Firmenkonten ermitteln

Eine Tupel-Suche soll drei "statistische Kennzahlen" zu den im System gepflegten Adressen von Firmen ermitteln:

  • Anzahl aller Firmen (Spalte: COMPANIES)

  • Anzahl aller Firmen in deren Adresse (address) ein Land im Feld "Land" (countryCode) ausgewählt ist (Spalte: WITH_COUNTRY)

  • Anzahl der unterschiedlichen Land-Werte im Feld "Land" (countryCode) in den Adressen von Firmen (Spalte: COUNTRIES)

Laufzeitbeispiel:

Die Kennzahlen für die Auswertung soll alle Firmen "aggregieren", für die im Ausführungskontext Lesezugriff besteht.

Das bedeutet:

  • Die Suche kommt ohne Gruppierung aus.

  • Es ist nur genau eine Ergebniszeile zu erwarten (s. Beispieldaten), sofern überhaupt eine Firma (mit Lesezugriff) existiert.

   <core:TupleSearchResult maxResults="100" count="1">
<columns>
<name>COMPANIES</name>
<name>WITH_COUNTRY</name>
<name>COUNTRIES</name>
</columns>
<result>
<row>
<item xsi:type="xsd:long">40</item>
<item xsi:type="xsd:long">28</item>
<item xsi:type="xsd:long">10</item>
</row>
</result>
</core:TupleSearchResult>

Konfiguration:

Für die Ausgabespalten der Tupel-Suche werden drei Projektionen vom Typ Aggregation benötigt:

Die Spalte COMPANIES soll die Anzahl aller ausgewerteten Firmen wiedergeben.

Der Typ "Anzahl" ermöglicht dies in Verbindung mit einer Feldprojektion, die sich auf das Feld "ID" (id) der Firma bezieht. Das Ergebnis liefert die Anzahl der Firmen, für die Lesezugriff besteht, unter zwei Voraussetzungen:

  1. Die Projektion liefert für keine Firma "Kein Wert" ($null), was für das "ID"-Feld sicher zutrifft.

  2. Je Firma tritt immer genau eine Ergebniszeile auf. Das trifft zu, solange keine Projektionen auf mehrwertige Felder verwertet werden (s. folgende Variante).

images/download/attachments/157877408/image-2023-11-15_12-57-25-version-1-modificationdate-1700049446061-api-v2.png

Die Spalte WITH_COUNTRY soll die Anzahl aller ausgewerteten Firmen wiedergeben, in deren Adressfeld "Land" (countryCode) ein Land ausgewählt ist.

Da der Typ "Anzahl" nur die Werte aus der Projektion berücksichtigt, die nicht $null sind, liefert er mit er Feldprojektion auf den Pfad zum fraglichen Feld (address.countryCode) genau die gesuchte Anzahl, solange gewährleistet ist, dass keine der anderen Projektionen ein mehrwertiges Feld betrifft (s. folgende Variante).



images/download/attachments/157877408/image-2023-11-15_12-58-10-version-1-modificationdate-1700049490858-api-v2.png

Die Spalte COUNTRIES soll die Anzahl der unterschiedlichen "Länder" angeben, die in den Adressen der ausgewerteten Firmen vorgefunden werden.

Der Typ "Anzahl (unterschiedlich)" (COUNT_DISTINCT) ermöglicht in Verbindung mit einer Feldprojektion, die sich - wie in der vorherigen Spalte - auf das Adressfeld "Land" (countryCode) bezieht.

WICHTIG◄ Der Zustand, dass in der Adresse kein Land angegeben ist, wird nicht mitgezählt. Falls die "Anzahl (unterschiedlich)" den Wert 1 ergibt, bedeutet das also nicht, dass alle Firmen in demselben Land verortet sind, sondern nur, dass keine Firmenadresse sich auf ein anderes Land bezieht.

Im Unterschied zum Typ "Anzahl" ist der Typ "Anzahl (unterschiedlich)" grundsätzlich robust gegen das Szenario, dass eine mehrwertige Projektion mehrere Ergebniszeilen je Firma erzeugt (s. folgende Variante). Die Vielfalt der Werte in der Projektion erhöht sich durch eine wiederholte Nennung derselben Werte nicht.

images/download/attachments/157877408/image-2023-11-15_12-58-22-version-1-modificationdate-1700049503083-api-v2.png

Variante:

Ausgehend von der bestehenden Konfiguration soll eine weitere Ausgabespalte (HAS_PARENT) hinzugefügt werden, die die Anzahl der Firmen angibt, deren Listenfeld "Übergeordnete Firmen" (parentCompanies) mindestens einen Eintrag enthält.

Angelehnt an die Projektion für die Spalte WITH_COUNTRY könnte man versuchen, die Anzahl der Firmen mit gefülltem "Übergeordnete Firmen" (parentCompanies) wie rechts abgebildet zu ermitteln.


images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg ACHTUNG images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg Dieser Ansatz funktioniert formal "fehlerfrei", liefert dabei aber keineswegs die erwarteten Ergebnisse.


Es wichtig zu verstehen, was passiert, wenn man die rechts abgebildete Projektion den bestehenden (s. oben) hinzufügt.

Mit denselben Firmendaten wie im obigen Laufzeitbeispiel liefert die erweiterte Tupel-Suche folgendes Ergebnis:

images/download/attachments/157877408/image-2023-11-16_9-56-8-version-1-modificationdate-1700124969484-api-v2.png

   <core:TupleSearchResult maxResults="100" count="1">
<columns>
<name>COMPANIES</name>
<name>WITH_COUNTRY</name>
<name>COUNTRIES</name>
<name>HAS_PARENT</name>
</columns>
<result>
<row>
<item xsi:type="xsd:long">57</item>
<item xsi:type="xsd:long">45</item>
<item xsi:type="xsd:long">10</item>
<item xsi:type="xsd:long">46</item>
</row>
</result>
</core:TupleSearchResult>

Ohne den direkten Vergleich zum vorherigen Ergebnis machen die Ergebnisdaten einen durchaus "unverdächtigen" Eindruck.

Allerdings liefern die Spalten COMPANIES und WITH_COUNTRY jetzt höhere Werte (57←40 und 45←28) als vor der Erweiterung, ohne dass zusätzliche Firmen erstellt oder deren Adressen bearbeiten worden wären.

Warum? Die hinzugefügte Aggregation bezieht sich per Feldprojektion auf ein mehrwertiges Feld (s. a. Datentyp Long[] im Screenshot oben), was sinngemäß eine Multiplikation der vorherigen Ergebniszeilen für Firmen mit der zugehörigen Liste von Long-Referenzen für übergeordnete Firmen bewirkt.

Die Aggregationsfunktionen verarbeiten das Ergebnis des "Kreuzprodukts": {Firmen} x {Übergeordnete Firmen}

Die unmittelbar bzw. in einer (1:1)-Relation mit der Firma verknüpften Daten (hier: die Feldwerte für id und address.countryCode) werden in so vielen Ergebniszeilen wiederholt, wie "Übergeordnete Firmen" für die betreffende Firma referenziert sind.

  • Für die COMPANIES-Spalte würde ein Wechsel zum Typ "Anzahl (unterschiedlich)" Abhilfe schaffen, da die Aggregation dann nur die Zahl der unterschiedlichen "ID"-Werte liefert.

  • Die Fehlanzeigen für die WITH_COUNTRIES-Spalte und die neue HAS_PARENT-Spalte können nicht so einfach "kuriert" werden.

  • Die COUNTRIES-Spalte zeigt einen unveränderten Wert an, weil hier sowieso der Typ "Anzahl (unterschiedlich)" ausgewählt ist.

Die folgende Konfiguration für die HAS_PARENT-Spalte verhindert die Multiplikation der Ergebniszeilen vor der Aggregation und sorgt dafür, dass die Suche insgesamt korrekte Daten liefert:


images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg ACHTUNGimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg Falls das verwendete Datenbanksystem die Verwendung der Subselect Projektion innerhalb einer Aggregationsfunktion nicht unterstützt, tritt eine Fehlermeldung auf. Dies ist z. B. für MSSQL der Fall (s. "Alternative Konfiguration" weiter unten).


Konfiguration:

Eine Aggregation mit dem Typ "Anzahl" soll alle Firmen zählen, die über mindestens eine übergeordnete Firma verfügen.

Die Projektion muss zu diesem Zweck genau dann einen beliebigen von "Kein Wert" ($null) unterschiedlichen Rückgabewert liefern, wenn die Anzahl der übergeordneten Firmen >0 ist.

  • Die Wenn ( Case ) Projektion innerhalb der Projektion formuliert diese Bedingung über eine Feld Einschränkung und weist über eine Literale Projektion willkürlich einen Leerstring als Rückgabewert zu, wenn die Bedingung erfüllt ist. Anderenfalls lautet der Rückgabewert "Kein Wert" ($null).

  • Als Prüfwert für die Feld Einschränkung muss die Anzahl der parentCompanies des Firmenkontos ermittelt werden, auf das sich die übergeordnete Suche bezieht. Diese Anzahl kann im Kontext einer Aggregation nur über eine Subselect Projektion ermittelt werden. Das direkte Verschachteln von Aggregationsfunktionen ist nicht zulässig.

    • Als Entität für den Subselect ist wieder der Typ "Firmenkonto" ausgewählt.

    • Die Spaltenprojektion für Subselect definiert die Aggregation zum Ermitteln der "Anzahl" der übergeordneten Firmen (parentCompanies).

    • Die Parameter Feld für Join und Feld der Entität für Join fordern eine Übereinstimmung bzgl. des Felds "ID" (id). Der Subselect wird hier ausnahmsweise verwendet, um eine (1:1)-Relation abzubilden. Das innere Aggregationsergebnis ("Anzahl der übergeordneten Firmen") soll logischerweise genau der Firma zugeordnet werden, für die es erhoben wurde.

images/download/attachments/157877408/image-2023-11-16_10-50-55-version-1-modificationdate-1700128257111-api-v2.png

Alternative Konfiguration:

Nachdem nicht jedes Datenbanksystem den Einsatz einer Subselect Projektion innerhalb einer Aggregationsfunktion akzeptiert, soll die folgende Konfiguration zeigen, wie man im gegebenen Anwendungsfall auch ohne Subselect Projektion die gewünschten Ergebnisse erzielen kann.

Im bisherigen Ansatz wurde die Subselect Projektion eingesetzt, um das Multiplizieren von Eingangsdaten ("Kreuzprodukt" {Firmen} x {Übergeordnete Firmen}) für die Aggregationsfunktion zu vermeiden.

Der folgende alternative Ansatz nimmt das Multiplizieren der Eingangsdaten bewusst in Kauf und kompensiert dessen Wirkung durch Anpassungen bei Typ und Projektion für die Aggregationsfunktion.

Spalte

Bisherige Projektion

Umstellung

Angepasste Projektion

COMPANIES

images/download/attachments/157877408/image-2023-11-15_12-57-25-version-1-modificationdate-1700049446061-api-v2.png

Bisher konnten die Firmen per Typ "Anzahl" (COUNT) gezählt werden, weil je Firma genau eine Zeile ausgegeben wurde.

Die Aggregation wird jetzt umgestellt, auf den Typ "Anzahl (unterschiedlich)" (COUNT_DISTINCT), sodass jede von der Suche "gefundene" Firma (identifiziert über die eindeutige "ID") nur einmal in die Zählung eingeht.

images/download/attachments/157877408/image-2023-11-17_13-23-30-version-1-modificationdate-1700223810896-api-v2.png

WITH_COUNTRY

images/download/attachments/157877408/image-2023-11-15_12-58-10-version-1-modificationdate-1700049490858-api-v2.png

Die bisherige Aggregation hat den Effekt ausgenutzt, dass eine Aggregation mit dem Typ "Anzahl" (COUNT) nur Werte aus der Projektion zählt, die nicht "Kein Wert" ($null) sind.

Stattdessen prüfen wir jetzt innerhalb der Projektion über eine Fallunterscheidung per Wenn ( Case ) Projektion ausdrücklich fest, ob das auszuwertende Adressfeld "Land" (countryCode) einen Wert enthält. Nur dann soll die Wenn ( Case ) Projektion die "ID" (id) der Firma Rückgabewert an die Aggregation übergeben.

Für die Aggregation wird der Typ umgestellt auf "Anzahl (unterschiedlich)" (COUNT_DISTINCT). Dies kompensiert die Mehrfachnennung desselben "ID"-Werts, falls der Rückgabewert "multipliziert" wird, weil die zusätzliche Projektion für die Spalte HAS_PARENT (s. ganz unten) mehrere "Übergeordnete Firmen" vorfindet.

images/download/attachments/157877408/image-2023-11-17_13-28-27-version-1-modificationdate-1700224107842-api-v2.png

COUNTRIES


images/download/attachments/157877408/image-2023-11-15_12-58-22-version-1-modificationdate-1700049503083-api-v2.png

Die Projektion für die Spalte COUNTRIES kann unverändert beibehalten werden, da hier der Typ "Anzahl (unterschiedlich)" (COUNT_DISTINCT) bereits verwendet wird.

An der Vielfalt der Länder änder auch ein Multiplizieren der Eingangswerte für die Aggregation nichts.

unverändert:
images/download/attachments/157877408/image-2023-11-15_12-58-22-version-1-modificationdate-1700049503083-api-v22.png

HAS_PARENT

bisher nicht vorhanden
(bzw. per
Subselect Projektion realisiert; s. oben)

Die Projektion für die Spalte HAS_PARENT reproduziert das Konzept für die Spalte WITH_COUNTRY:

  • In der Projektion wird die Liste "Übergeordnete Firmen" (parentCompanies) per Wenn ( Case ) Projektion auf Inhalt geprüft.

  • Die Feld Einschränkung trifft für jede aufgelistete Referenz für eine übergeordnete Firma zu. Nur dann soll die Wenn ( Case ) Projektion die "ID" (id) der untergeordneten Firma Rückgabewert an die Aggregation übergeben.

  • Die Aggregation verwendet den Typ "Anzahl (unterschiedlich)" (COUNT_DISTINCT), sodass jede ID einer "untergeordneten" Firma nur einfach in die Zählung eingeht. Die IDs von Firmen ohne übergeordnete Firma tauchen in der Zählung sowieso nicht auf, weil in der Wenn ( Case ) Projektion kein ELSE-Zweig mit einer Projektion vorhanden ist.

images/download/attachments/157877408/image-2023-11-17_13-44-48-version-1-modificationdate-1700225088818-api-v2.png