Sie sind nun wieder eingeladen, die Diskussion spezieller technischer Probleme mit zu verfolgen. Bitte schicken Sie Fragen, Anregungen oder Antworten zu den vorgestellten Themen – ebenso wie Ihre Kritik – an unsere e-Mail-Adressen: dieter.bender@MidrangeMagazin.de oder Redaktion@MidrangeMagazin.de
Frage:
Ich habe versucht, mit SQL die Anzahl der Kunden zu ermitteln, die im Jahr 2001 eine Bestellung gehabt haben. Die Kunden aufzulisten, war mit folgender Abfrage kein Problem:
select distinct kunde_id
from kunde, bestellung
where kunde = kunde_id
and year(datum) = 2001
Doch mit der Anzahl habe ich ein Problem: Setze ich um „kunde_id“ die COUNT-Funktion, bekomme ich ein falsches Ergebnis. Ich habe noch ein geschachteltes SELECT versucht:
select count(*) from (select distinct kunde_id
from kunde, bestellung
where kunde = kunde_id
and year(datum) = 2001 )
Das brachte jedoch die mir unverständliche Fehlermeldung: Token
Antwort: Mit beiden Varianten waren Sie nahe am Ziel. Bei der ersten Variante muss man lediglich das Schlüsselwort DISTINCT mit in die Klammer der COUNT-Funktion hineinnehmen und dann bekommt man das richtige Ergebnis.
select count(distinct kunde_id)
from kunde, bestellung
where kunde = kunde_id
and year(datum) = 2001
Bei der zweiten Variante muss man beim DB2/400 dem Resultset einen Namen verpassen, um dem SQL-Interpreter auf die Sprünge des Standards zu helfen. Der SQL-Standard fordert, dass überall, wo ein Tabellenname stehen darf, auch eine Tabelle – also auch ein Subselect – stehen darf. In solchen Fällen fordert der SQL-Interpreter der AS/400 dann einen Alias als Name für die Tabelle.
select count(*)
from
(
select distinct kunde_id
from kunde, bestellung
where kunde = kunde_id
and year(datum) = 2001
) as a
Die Verwendung der DISTINCT-Funktion macht die Abfrage allerdings eher langsam und kann in diesem Beispiel umgangen werden, was zu verbesserten Ausführungszeiten führen kann.
Dazu gibt es einmal die Variante mit der EXISTS-Klausel in der WHERE-Bedingung:
select count(*)
from kunde a
where exists
(
select kunde
from bestellung
where year(datum) = 2001
and kunde = a.kunde_id
)
Eine weitere Möglichkeit besteht in der Verwendung der IN-Klausel in der WHERE-Bedingung:
select count(kunde_id)
from kunde
where kunde_id in
(
select kunde
from bestellung
where year(datum) = 2001
)
Die letzten beiden Varianten benötigten in einer Testumgebung bei mir nur die Hälfte der Zeit – wie die beiden ersten Varianten. Man sieht daran, dass der SQL-Interpreter noch ein Stück davon entfernt ist, Abfragen an der Ergebnismenge orientiert zu optimieren. Umso wichtiger ist es, SQL-Abfragen in Views zu maskieren oder in einer schmalen Schicht der Anwendung zu kapseln, damit man Optimierungen leicht durchführen kann.
Wichtig ist es in jedem Fall, dass ein hinreichender PTF-Stand installiert ist; bei Nutzung von SQL müssen in jedem Fall zusätzlich zu den kumulativen PTFs Gruppen-PTFs für die Datenbank eingespielt werden. Diese heißen für Version 5.1 SF99501 und für Version 5.2 SF99502; der Stand kann in der gleichnamigen DTAARA in der Bibliothek QSYS nachgesehen werden. Ich stelle immer wieder fest, dass diese wichtigen PTFs auf vielen Maschinen fehlen, weil viele Systembetreuer davon ausgehen, dass alle wichtigen PTFs in den kumulativen Ständen enthalten sind. Das ist bereits seit Version 4 nicht mehr gewährleistet; für die Datenbank, bei der Verwendung von Java und für den http-Server sind separate Fixpacks erforderlich.
Den Autor Dieter Bender erreichen Sie unter dieter.bender@midrangemagazin.de