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.
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 |
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. |
|
Arithmetik (für einzelnen Zahlenwert) |
|||
Absolut |
ABS |
numerisch |
Gibt den Absolutbetrag eines Zahlenwerts zurück |
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.
|
Typ |
AggregateType
|
Der Typ bestimmt welche Art von Aggregation, Berechnung under Umwandlung auf Basis der Projektion vorgenommen werden soll.
►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.
|
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:
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:
|
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. |
|
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:
►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". |
|
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":
|
|
Laufzeitbeispiel: ID,VOLUME,COMPLEXITY 8455,1,2.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:
|
|
►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:
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:
|
|
Als Projektionen für die CSV-Suche sollen die folgenden beiden Spalten ausgegeben werden:
|
|
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:
|
|
►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 (!=):
►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. |
|
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:
|
<core:TupleSearchResult maxResults="100" count="3"> |
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:
|
|
Das Screenshot rechts zeigt eine Übersicht über die für die Tupel-Suche eingerichteten Projektionen, die die Ausgabespalten definieren:
|
|
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. |
|
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. |
|
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. |
|
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:
|
<core:TupleSearchResult maxResults="100" count="1"> |
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:
|
|
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). |
|
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. |
|
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.
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: |
|
<core:TupleSearchResult maxResults="100" count="1"> |
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.
|
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:
ACHTUNG
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.
|
|
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 |
|
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. |
|
WITH_COUNTRY |
|
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. |
|
COUNTRIES |
|
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: |
HAS_PARENT |
bisher nicht vorhanden |
Die Projektion für die Spalte HAS_PARENT reproduziert das Konzept für die Spalte WITH_COUNTRY:
|
|