Query - Relation (Beziehung)

In den BO-Views sind Attribute wie beispielsweise Addr.CustBoId nicht mehr verfügbar.
Diese "Hilfs-Attribute" wurden ursprünglich eingeführt, um innerhalb von GetBo-Abfragen direkt auf andere BOs zugreifen zu können.
Beispiel: Bei der Abfrage von Adressen (Addr) kann direkt auf Attribute des Kunden (Cust) zugegriffen werden: Cust.Remark(Addr.CustBoId)
Bei den BO-Views stehen stattdessen vordefinierte Relationen zur Verfügung.
Beispiel: Die BO-View "Addr" verfügt über die Relation "Cust". Damit kann bei Query-Abfragen von Adressen, direkt auf Attribute des Kunden zugegriffen werden. Dies sogar ohne Angabe einer Referenz.

Vordefinierte Relationen

Für Query-Abfragen sind bereits sehr viele vordefinierte Relationen vorhanden. Über GetInfoQueryViewRel können Sie sich diese vordefinierten Relationen anzeigen lassen. Betrachten wir das am Beispiel der View "Addr":
Die View "Addr" verfügt (gem. GetInfoQueryViewRel) über folgende vordefinierte Relationen:
GetInfoQueryViewRel_01.jpg
Eine vordefinierte Relation bedeutet, dass Sie bei Query-Abfragen auf "Addr", auch Attribute von Views verwenden können, die via vordefinierte Relation verbundenen sind.
Beispiel:
Es wird eine Query-Abfrage auf "Addr" gemacht. Für jede gefundene Adresse sollen Adress-Nr., Nachname, Ländercode und Länder-Bezeichnung ausgegeben werden.
Die Länder-Bezeichnung steht dabei in einer anderen View (Country), welche von der Adresse her, über den Ländercode verbunden ist (Relation).
Query
Query
Main=Addr
MaxRows=5
Filter=Addr.Number > 1069
Columns=Addr.Number,Addr.LastName,Addr.CountrySc
Column=Land,Country.Name
Resultat
Addr.Number Addr.LastName Addr.CountrySc Land
2010
Hintermoser
AT
Österreich
2011
Langhammer
CH
Schweiz

Zusatzinformationen

Die Beschreibung der jeweiligen Relation finden sie in der entsprechenden Rückgabe-Spalte von GetInfoQueryViewRel. Nehmen wir als Beispiel wieder die View "Addr". Die vordefinierte Relation auf die Kontaktperson bildet sich folgendermassen:

Zusätzliche Prüfung mit "exists"

Betrachten wir nun eine andere vordefinierte Relation. Nämlich diejenige auf die Kontaktpersonen (View: Contact)
Die vordefinierte Relation liefert jeweils nur den Hauptkontakt. Ist kein Hauptkontakt definiert, wird nichts zurückgegeben.
Query
Query
Main=Addr
MaxRows=10
Filter=Addr.Number>1000
Columns=Addr.Number, Addr.LastName
Column=,Contact.LastName
OrderBy=Addr.Number
Resultat
Addr.Number Addr.LastName Contact.LastName
1001
Werkzeug AG
Meier
1002
Tool AG
1003
Fein-Werkzeuge AG
1004
Trichter
1005
MAAP Maschinen und Apparate
Heer
1006
Andres AG - Autoservice
Sieber
1007
Hilti Vertriebs AG
Maurer
1008
Heldner
1009
Gisler
1010
Gmür
Es sollen nun aber nur noch diejenigen Adressen zurückgegeben werden, bei welchen ein Hauptkontakt hinterlegt ist.
Das kann über ein zusätzliches Filter-Kriterium erreicht werden.
Filter=Addr.Number>1000 and Addr.MainContactNo>0
Diese Erweiterung des Filters ist prinzipiell nicht falsch, aber in Bezug auf Performance nicht optimal.
Viel besser ist es, in diesen Fällen mit "exists()" zu arbeiten. (Siehe auch: Set-Funktionen)
Query
Query
Main=Addr
MaxRows=10
Filter=Addr.Number>1000 and exists(Contact)=1
Columns=Addr.Number, Addr.LastName
Column=,Contact.LastName
OrderBy=Addr.Number
Resultat
Addr.Number Addr.LastName Contact.LastName
1001
Werkzeug AG
Meier
1005
MAAP Maschinen und Apparate
Heer
1006
Andres AG - Autoservice
Sieber
1007
Hilti Vertriebs AG
Maurer
1016
Schreinerei Hügli
Hügli
1017
Distributa AG
Bachmann
1018
BEWE AG
Meyer
1020
Bosch Elektro GmbH
Menzi
1024
Distributa Konzern AG
Fankhauser
1028
Klarsicht AG
Meiershofer

Eigene Relationen

Sind keine vordefinierten Relationen verfügbar, können Sie eigene Relationen bilden. Bedingung für eine eigene Relation ist, dass Sie mit Attributen des Main-BO eine Referenz (Relation) auf das gewünschte BO bilden können.
Relationen werden nach folgendem Schema definiert:
Related=<Alias>,<Source>,<Count>,<OrderArray>,<FilterExpression>
Achtung
Achtung
Versuchen Sie, wenn immer möglich, auf indexierte Attribute zu referenzieren. Ansonsten resultieren u.U. sehr lange Laufzeiten für Query-Abfragen.
Relation auf eine Adresse über ein indexiertes Attribut: Related=RelAddr,Addr,One,,RelAddr.LastName = Addr.LastName
Relation auf eine Adresse über ein nicht indexiertes Attribut: Related=RelAddr,Addr,One,,RelAddr.Free4 = Addr.LastName
Die zweite Relation führt bei einer Query-Abfrage zu einer sehr langen Laufzeit.
Wichtig
Wichtig
Die Verwendung von Relationen hat einen direkten Einfluss auf das Laufzeitverhalten von Query-Abfragen. Implementieren Sie deshalb nicht zu viele Relationen innerhalb einer Query-Abfrage.
Bei "normalen" Query-Abfragen sollten Sie sich an einen "Richtwert" von maximal fünf Relationen halten. Für "anspruchsvolle" Query-Abfragen (wie z.B. MIS) sollten Sie sich an einen "Richtwert" von maximal zwölf Relationen halten.
Argument Beispiel
<Alias>
Bezeichner der Relation.
<Source>
Gewünschte View (auf die referenziert wird)
KorrespondenzPerson

                              
Contact
<Count>
Anzahl Elemente.
Mögliche Werte: One, ToOne, First, Last, All, 0 - n
All

                              
Default: (wenn leer) One
Hinweis
Hinweis
Beachten Sie, dass Count=All und Count=One nicht funktionieren, wenn mit OrderArray gearbeitet wird.
<OrderArray>
Gewünschte Sortierung.
[+Contact.LastName,-Contact.Number]
Wichtig
Wichtig
Wird mit OrderArray gearbeitet, müssen die Attribute zwischen eckige Klammern gesetzt werden.
Siehe auch hier: Verwendete Definitionen
Beachten Sie, dass Count=All und Count=One nicht funktionieren, wenn mit OrderArray gearbeitet wird.
<FilterExpression>
Filter für die Relation.
Über den Filter wird die Verbindung vom Main-BO auf das referenzierte BO hergestellt.
Contact.AddrNo=Addr.Number and Contact.IsMainContact=1
Beispiel 1:
Über eine eigene Relation sollen nur Adressen ausgegeben werden, bei denen eine Kontaktperson als Hauptkontakt erfasst ist.
Query
Query
Main=Addr
MaxRows=10
Filter=Addr.Number>1000 and KorrespondenzPerson.IsMainContact=1
Columns=Addr.Number, Addr.LastName
Related=KorrespondenzPerson,Contact,All,,KorrespondenzPerson.AddrNo=Addr.Number and KorrespondenzPerson.IsMainContact=1
Column=,KorrespondenzPerson.LastName
Resultat
Addr.Number Addr.LastName KorrespondenzPerson.LastName
1001
Werkzeug AG
Meier
1005
MAAP Maschinen und Apparate
Heer
1006
Andres AG - Autoservice
Sieber
1007
Hilti Vertriebs AG
Maurer
1016
Schreinerei Hügli
Hügli
1017
Distributa AG
Bachmann
1018
BEWE AG
Meyer
1020
Bosch Elektro GmbH
Menzi
1024
Distributa Konzern AG
Fankhauser
1028
Klarsicht AG
Meiershofer
Beispiel 2:
Auf dem freien Attribut 7 eines Verkaufsdokuments (SalDoc.Free7) ist eine Adress-Nr. hinterlegt. Über die BO-Redefinition ist diese als "Abladeort" bezeichnet.
Es wird eine Query-Abfrage auf SalDoc gemacht. Dabei sollen von der Adresse (Adress-Nr. in SalDoc.Free7) folgende Attribute ausgegeben werden:
  • Addr.FullName
  • Addr.Zip
  • Addr.City
Bei der Query-Abfrage wird nun für die Adress-Nr. im freien Attribut 7 ein Alias verwendet.
Query
Query
Main=SalDoc
MaxRows=All
Columns=SalDoc.InternalNo,SalDoc.Free7,AbladeOrt.FullName,AbladeOrt.Zip,AbladeOrt.City
Filter=SalDoc.InternalNo=12342
Related=AbladeOrt,Addr,,,AbladeOrt.Number = SalDoc.Free7
Resultat
SalDoc.InternalNo SalDoc.Free7 Abladeort.FullName Abladeort.Zip Abladeort.City
12342
1040
Cantina Zocchi
6716
Acquarossa
Wichtig
Wichtig
Wenn mehrmals mit demselben BO gearbeitet wird, empfehlen wir dringend, einen Alias zu verwenden. Im obigen Beispiel ist "Abladeort" der Alias für die Adresse (Addr) welche sich hinter dem freien Attribut (SalDoc.Free7) "versteckt". Wenn Sie nun zusätzlich auch noch mit der Kundenadresse arbeiten möchten, beugt die Verwendung eines Alias Verwechslungen vor.

Eigene Relation über mehrere BOs hinweg

Eigene Relationen sind auch über mehrere BOs hinweg möglich.
Anforderung: Ausgeben von Attributen der privaten Adresse einer Kontaktperson. Die Kontaktperson befindet sich dabei in einem Adresspool.
Referenz: Adresspool-Eintrag -> Kontaktperson -> Private Adresse der Kontaktperson
Die Query-Abfrage enthält nun zwei Relationen (Related)
Query
Main=AddrPoolItem
Columns=AddrPoolItem.AddrNo, AddrPoolItem.ContactNo,MyContact.PrivateAddrNo,PrivateAddr.FirstName,MyContact.LastName
MaxRows=10
Filter=AddrPoolItem.AddrPoolNo=10
Related=MyContact,Contact,1,,MyContact.Number=AddrPoolItem.ContactNo and MyContact.AddrNo = AddrPoolItem.AddrNo
Related=PrivateAddr,Addr,1,,PrivateAddr.Number=MyContact.PrivateAddrNo
Resultat
AddrPoolItem.AddrNo AddrPoolItem.ContactNo MyContact.PrivateAddrNo PrivateAddr.FirstName PrivateAddr.LastName
1070
2
100700
Hans-Heinz
Huber
Erste Relation: Adresspool-Eintrag -> Kontaktperson
MyContact,Contact,1,,MyContact.Number=AddrPoolItem.ContactNo and MyContact.AddrNo = AddrPoolItem.AddrNo
Dabei wird die BoId der gesuchten Kontaktperson (Adressnummer, KP-Nummer) mit "and" zusammengestellt.
Zweite Relation: Kontaktperson -> Private Adresse der Kontaktperson
PrivateAddr,Addr,1,,PrivateAddr.Number=MyContact.PrivateAddrNo

Rückgabespalten von Relationen definieren (RelatedColumn)

Diese Funktionalität steht ab v15.10.03 zur Verfügung!
Das Query-Argument RelatedColumn ermöglicht Ihnen, die Angabe spezifischer Spalten aus einer Relation und damit auch das Filtern und Bilden von Aggregationen auf einzelnen Relationen.
Relationen auf spezifische Spalten werden (analog Column) nach folgendem Schema definiert:
RelatedColumn=<Alias>,<Expression>
Die Definition einer RelatedColumn bezieht sich dabei jeweils auf die vorangegangene Related-Definition.
Hinweis
Hinweis
Via RelatedColumn definierte Spalten werden nicht automatisch in das Query-Resultat übernommen.
Falls das gewünscht ist, müssen diese Spalten ganz normal mittels Columns bzw. Column als Bestandteil des Resultats definiert werden.
Beispiel einer Query-Abrage mit Kumulation (sum) auf RelatedColumn:
Es wird die Summe aller Rechnungen (SalDoc.TotalInclVat) pro Kunde (Adresse) gebildet.
Query
Main=Addr
MaxRows=All
Filter=SalDocRel.Total > 0
Columns=Addr.Number,SalDocRel.Total
Related=SalDocRel,SalDoc,,,SalDocRel.CustNo = Addr.Number and SalDocRel.SalProcLevelCd = 4 and SalDocRel.DocStateCd > 10 and SalDocRel.IsUndo = FALSE
RelatedColumn=Total,ifnull(sum(SalDocRel.TotalInclVat),0)
OrderBy=-SalDocRel.Total
Achtung
Achtung
Wenn für eine Relation keine Rows gefunden werden, liefern die Aggregat-Funktionen NULL zurück.
Wird dieser Fall nicht behandelt, entsteht daraus via Query-Aufruf ein Leerstring.
Es wird deshalb dringend empfohlen, eine Prüfung auf NULL zu implementieren. Siehe im obigen Beispiel: ...ifnull(sum(...),0)
Beachten Sie auch, dass bei grossen Datenvolumen Queries mit langer Laufzeit entstehen können!
Beispiel einer Query-Abfrage mit Kumulation (sum) auf RelatedColumn:
Es werden Kumulationen für jeden Warehouse-Lagerplatz gebildet. Dies jeweils für alle Belegungen und für alle "Reservationen".
Query
Main=StorageBin
MaxRows=10
Columns=StorageBin.Number
Column=GrosseHoeheBelegt,if(StorageBinAssignmentSum.Height>100,TRUE,FALSE)
Column=KeineHoeheBenoetigt,if(WhTransaction.HeightSum=0,TRUE,FALSE)

Columns=StorageBinAssignmentSum.Height,StorageBinAssignmentSum.Weight,StorageBinAssignmentSum.Volume
Related=StorageBinAssignmentSum,StorageBinAssignment,,,StorageBinAssignmentSum.StorageBinNo = StorageBin.Number
RelatedColumn=Height,ifnull(sum(StorageBinAssignmentSum.Height),0)
RelatedColumn=Weight,ifnull(sum(StorageBinAssignmentSum.Weight),0)
RelatedColumn=Volume,ifnull(sum(StorageBinAssignmentSum.Volume),0)

Columns=WhTransaction.HeightSum,WhTransaction.WeightSum,WhTransaction.VolumeSum
Related=WhTransaction,WhTransaction,,,WhTransaction.InStorageBinNo = StorageBin.Number and WhTransaction.TransferCompleted = FALSE
RelatedColumn=HeightSum,ifnull(sum(WhTransaction.Height),0)
RelatedColumn=WeightSum,ifnull(sum(WhTransaction.Weight),0)
RelatedColumn=VolumeSum,ifnull(sum(WhTransaction.Volume),0)

Filter=(GrosseHoeheBelegt=TRUE) and (KeineHoeheBenoetigt=FALSE)