Seite 1 von 3
Gibt es die Möglichkeit einer Schleife?
Verfasst: Mo 12. Aug 2024, 12:32
von waldi969
Hallo an alle,
ich würde gern eine Abfrage, welche mit PHP sehr lange dauert verbessern. Es gibt in PHP eine Schleife, welche für jeden Monat im Jahr eine Abfrage durchführt:
Code: Alles auswählen
SELECT distinct count(adressnr) from Beleg WHERE belegtyp = 'V' and belegart = 'AU' and getmonth(belegdat) = '7' AND getyear(belegdat) ='24' and Adressnr not IN (SELECT Adressnr FROM Beleg where belegdat between '01.01.2000' and '30.06.2024'
Der Teil in Klammern ist immer einen Monat kleiner als die Hauptabfrage.
Gibt es eine Möglichkeit, diese Abfrage für alle 12 Monate durchzuführen? Zum Beispiel mit einer Schleife?
Ergebnis sollte sein
oder
Vielen Dank für eure Hilfe!
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mo 12. Aug 2024, 15:13
von bfuerchau
Ich verstehe die Frage nicht.
Lass die Prüfung für GetMonth einfach weg und mach einen GrupBy draus,
select GetMonth(..), count (distinct ,,,)
from
where ...
gropu by 1
Deine Abfrage dauert wahrscheinlich so lange, da für diese Whereklausel kein passender Index gefunden wird.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Di 13. Aug 2024, 07:31
von waldi969
Die Abfrage prüft die Anzahl der Neukunden im Monat, das heißt, im geklammerten not in Teil, wird überprüft, ob es die Adressnr schon einmal gab. Der Zeitraum im not in Teil liegt also vor diesem Monat. Das Bestandskunden die vorhandene Adressnr bekommen, wird bei der Eingabe geprüft.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Di 13. Aug 2024, 08:04
von martin.koeditz
Alternativ kannst du auch mit Unterabfragen arbeiten. Die Performance ist allerdings schlechter als mit den vorher genanten Group-Funktionen.
Eine Unterabfrage könnte zum Beispiel so aussehen (ich habe dies syntaktisch nicht geprüft):
Code: Alles auswählen
SELECT
count((select from Beleg WHERE belegtyp = 'V' and belegart = 'AU' and getmonth(belegdat) = '1' AND getyear(belegdat) ='24' and Adressnr not IN (SELECT Adressnr FROM Beleg where belegdat between '01.01.2000' and '30.06.2024')) COUNT_01,
count((select from Beleg WHERE belegtyp = 'V' and belegart = 'AU' and getmonth(belegdat) = '2' AND getyear(belegdat) ='24' and Adressnr not IN (SELECT Adressnr FROM Beleg where belegdat between '01.01.2000' and '30.06.2024')) COUNT_02,
count((select from Beleg WHERE belegtyp = 'V' and belegart = 'AU' and getmonth(belegdat) = '3' AND getyear(belegdat) ='24' and Adressnr not IN (SELECT Adressnr FROM Beleg where belegdat between '01.01.2000' and '30.06.2024')) COUNT_03
FROM RDB$DATABASE
Gruß
Martin
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Di 13. Aug 2024, 10:02
von waldi969
Mit Indexen kenn ich mich leider nicht aus, die Unterabfragen klappen aber prima! Die Zeit ist auch halbwegs in Ordnung!
DANKE!!!
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Di 13. Aug 2024, 18:57
von bfuerchau
Statt "not in" kann man auch
not exists (select * from .... where outerkey = innerkey)
verwenden. Hier wird dann nur 1 Select gemacht, da der ja bereits ausreicht.
Bei "Not In " muss gegen die ganze Liste geprüft werden.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 09:49
von martin.koeditz
Statt "not in" kann man auch
not exists (select * from .... where outerkey = innerkey)
verwenden. Hier wird dann nur 1 Select gemacht, da der ja bereits ausreicht.
Bei "Not In " muss gegen die ganze Liste geprüft werden.
Stimmt.

Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 12:43
von bfuerchau
Seit Einführung von "[not] exists (select * ...)" macht ein "[not] in (select x ....)" keinen Sinn mehr. In-Listen lohnen nur noch mit Konstanten.
Warum?
"In" muss alle Werte prüfen, die gefunden werden, da auch der letzte Wert geprüft werden muss. In der Regel wird das nur über Index optimiert (where) ansonsten erfolgt ein Tablescan. Die Prüfung muss dann für jede Zeile einzeln wiederholt werden.
Bei einem exists wird halt nach der ersten Existenz oder der Nichtexistenz aufgehört.
Hier empfielt sich geradezu, bei Tabellen ab mehreren 1000 Zeilen ein Index für die Prüffelder anzulegen, da dies dann nur 1 Zugriff ist.
Fazt: in (select ) durch exists (select ) ersetzen.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 13:37
von waldi969
Danke für die Erklärung. "not exists" habe ich bisher noch nicht genutzt. Aus einer Seminar PDF, wo ich die Syntax der "not exists" mit anschauen wollte, habe ich folgendes Zitat:
EXISTS-Abfragen benötigen mehr Rechnerzeit und werden zweckmässigerweise durch INAbfragen
ersetzt:
Ich versuche die Abfrage nach "not exists" umzustellen und werde dann berichten

Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 14:49
von waldi969
Ich habe die SQL gerade umgestellt und in meine NodeJS API eingebaut, es wird ca. die gleiche Zeit angezeigt. Also keine Verbesserung. Beispiel alt:
Code: Alles auswählen
SELECT 2024 as jahr,
(select distinct count(adressnr) from Beleg WHERE and getmonth(belegdat) = '1' AND getyear(belegdat) ='2024' and Adressnr not IN (SELECT Adressnr FROM Beleg where getdate(belegdat) < '01.01.2024')) as jan, ... alle Monate
FROM RDB$DATABASE
zu
Code: Alles auswählen
SELECT 2024 as jahr,
(select count(b.adressnr) from Beleg b WHERE getmonth(b.belegdat) = '1' AND getyear(b.belegdat) = 2024 and not exists (SELECT be.adressnr FROM Beleg be where be.adressnr = b.adressnr and getdate(be.belegdat) < '01.01.2024')) as jan, ... alle Monate
FROM RDB$DATABASE
alle Abfragen dauern ca. 3500 ms
Es wäre natürlich gut, wenn die Datenmenge kleiner wäre (dafür wäre ja der Index da). Ich könnte meine Selektion (mit Belegtyp, Belegart, Jahr,...) schon vorher ausführen und die SQL müsste nur die kleinere Datenmenge prüfen. Ich nutze in einem Programm die Firebird 2.5. Könnte mir jemand eine Typ geben, wie das machbar wäre? Google und Youtube bringt mich nicht gerade weiter.
Vielen Dank