Ich muss gestehen, dass ich nicht 100%ig verstehe, was du wirklich machen willst, denn wie du im Eingangspost schreibst, willst du
alle an einen bestimmten Kunden gelieferten Artikel jeweils
ein Mal anzeigen.
Dein Query selektiert allerdings nur die Artikel, die lediglich ein einziges Mal an den betroffenen Kunden im entsprechenden Zeitraum geliefert wurden:
HAVING (COUNT(A.ARTIKEL_NR)=1))
.
Ich gehe aber davon aus, dass du das machen willst, was du textuell beschrieben hast.
Wenn nicht, ist das Folgende nicht unbedingt relevant...
Window Functions sind mit Vorsicht zu genießen.
Wenn du keine Ressourcenprobleme auf deinen Datenbanken hast, oder dir die Zeitpunkte mit wenig Last rauspicken kannst, ist es egal, wie du deine SQLs formulierst, aber wenn du im produktiven Betrieb eines potentiell notorisch IT-unterfinanziernenden Unternehmens laufen musst, oder es zu jeder Zeit auf Performance ankommt, lass die Finger von überladenen Lösungen.
Um es möglichst kurz zu beschreiben:
Normale Selects gehen iterativ über die gewünschte Datenmenge und beschränken jegliche Operationen und Berechnungen auf die aktuelle Iteration, also den aktuellen Datensatz und schließen damit das Einbeziehen von Informationen außerhalb des aktuellen Datensatzes kategorisch aus.
Ein Select mit Group By geht ebenso iterativ über die gewünschte Datenmenge, jedoch mit dem Unterschied, dass die einzelnen Iterationen nach gewissen Kriterien gruppiert werden können und innerhalb der Gruppierungen Daten über Aggregationsfunktionen zusammengefasst werden können.
Beide landen nach O-Notation bei O(n), wobei das Select mit Group By natürlich aber etwas Zusatzarbeit und -ressourcen aufruft und u.U. stärker von Indizes bzw. vom Caching der aktuellen Tabelle im Puffer abhängt.
Ein Order By erhöht den Aufwand entsprechend, da die Datenmenge am Ende noch sortiert werden muss.
Der Aufwand steigt dann auf O(n) + O(n²) im Worst-Case und ist sehr stark abhängig vom Vorhandensein von Indizes für die Sortierkriterien bzw. vom Caching-Zustand der Tabelle.
Ein Select mit einer Window Function läuft nicht mehr iterativ ab.
Mit einer Window Function hast du, neben dem aktuellen Datensatz, Zugriff auf Informationen aus dem jeweilig vorhergehenden und nachfolgenden Datensatz.
D.h. nun, dass, egal was du machst, dieser Select implizit immer mit einem Order By ausgeführt wird, da sonst nicht die Möglichkeit bestünde, zu beurteilen, welcher Datensatz vor oder nach dem aktuellen steht.
Der Aufwand ist also immer mindestens O(2n) + O(n²) für einfache Window Functions bzw. O(3n) + O(n²) wenn auf Vorgänger und Nachfolger zugegriffen wird.
Ein Order By auf das Endergebnis erhöht den Aufwand entsprechend noch einmal um O(n²).
Eine Window Function ist in deinem Fall, zumindest, wie ich ihn verstehe, einfach nur Overkill und bringt zudem keinen erweiterten Nutzen.
Mein Tipp für solche Fälle: Select kann nicht einfach nur Daten aus Tabellen selektieren, sondern auch aus Views jeder Art und, hier besonders relevant, aus
anderen Selects!
D.h. du kannst zuerst ein Select formulieren, in dem nur die notwendigsten Daten bezogen werden, und die darüber selektierte Datenmenge wie einen normalen Table joinen:
SQL:
select /*Was auch immer*/
.
.
.
from ARTIKELC A
INNER JOIN (select distinct L.ARTIKELNR as ANR
from LFSCHEIN L
INNER JOIN KARTIKEL KA on KA.ARTIKEL_NR = L.ARTIKELNR
INNER JOIN KUNDENA K on K.KUNDEN_NR = KA.KUNDEN_NR
where K.KUNDEN_NR = 30002
AND L.LIEF_DATUM >= '01/01/2020') on ANR = A.ARTIKEL_NR
INNER JOIN \*BlaBlub*\ on \*Kriteria*\
.
.
.
order by L.ARTIKELNR
Besonders nützlich ist dieser Ansatz auch, wenn tatsächlich eine Gruppierung der Daten vollzogen werden muss und dabei aber auch Informationen einbezogen werden sollen, die schlicht nicht aggregiert werden können (z.B. Blobs o.ä.):
SQL:
select A.ARTIKEL_NR, CANR, A.BlobField
/*Was auch immer*/
.
.
.
from ARTIKELC A
INNER JOIN (select L.ARTIKELNR as ANR, Count(L.ARTIKELNR) as CANR
from LFSCHEIN L
INNER JOIN KARTIKEL KA on KA.ARTIKEL_NR = L.ARTIKELNR
INNER JOIN KUNDENA K on K.KUNDEN_NR = KA.KUNDEN_NR
where K.KUNDEN_NR = 30002
AND L.LIEF_DATUM >= '01/01/2020'
GROUP BY L.ARTIKELNR) on ANR = A.ARTIKEL_NR
INNER JOIN \*BlaBlub*\ on \*Kriteria*\
.
.
.
order by L.ARTIKELNR