Seite 2 von 3
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 15:50
von bfuerchau
Das ist schon sehr lang.
Hauptproblem ist, dass durch deine Where-Klauseln GetDate(xx) = yy kein Index verwendet werden kann und die Abfrage immer alle Zeilen liest.
Wofür brauchst du GetDate(x)?
Ist x keine Spalte vom Typ Date?
Statt GetMonth(datum) = x and GetYear(datum) = y kannst du auch ein
Datum >= '2024-nn-01' and Datum <= '2024-nn-MM')
machen. Hast du dann einen Index über "Datum" dauert die Abfrage eher Millisekunden.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 16:15
von waldi969
Das mit dem Datum ist kein Problem, nur mit dem Index
getMonth und getYear sind Zusatzfunktionen des Hersteller. Ein Datum von bis ist kein Problem, bringt aber ohne Index wahrscheinlich nicht viel, weil die Zeit so gleich bleibt.
Ich habe bei der Firebird Language Reference nachgeschaut, werde aber nicht schlau draus.
Optimum wäre ja eine Tabelle wo nur Belege des Jahres ... (z.B.: 2024) wären.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mi 14. Aug 2024, 17:44
von bfuerchau
Ist die Frage, ob du Änderungen in der DB machen darfst und kannst.
Indexerstellung ist allgemeingültig:
https://www.w3schools.com/sql/sql_create_index.asp
create index Tabellenname_Index on Tabellenname (Datumfeld);
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Do 15. Aug 2024, 00:18
von vr2
Vielleicht nochmal zurück zur Aufgabenstellung, ich denke, nur die Abfrage muss optimiert werden. Du willst die Anzahl der Neukunden in einem Jahr anhand der Belegtabelle ermitteln, nach Monat aufgeschlüsselt.
Dh, Du brauchst erstmal zu jeder Adressnr (gleich Kundennr in diesem Fall) das Datum der ersten Buchung, und zwar über den gesamten Zeitraum der Belegtabelle, jemand kann ja schon vor 10 Jahren etwas gebucht haben. Das bekommst Du so:
Code: Alles auswählen
select adressnr, min(belegdat) erste_buchung
from beleg
-- where belegtyp = 'V' and belegart = 'AU'
group by 1
Jetzt willst Du aber nur die Neukunden in einem Jahr wissen, zb in 2024. Dh, Du musst diese Menge einschränken auf die ersten Buchungen in 2024. Das sieht dann so aus:
Code: Alles auswählen
select adressnr, min(belegdat) erste_buchung
from beleg
-- where belegtyp = 'V' and belegart = 'AU'
group by 1
having extract(year from min(belegdat)) = 2024
Diese Menge musst Du jetzt nur nach Monat gruppieren und die Anzahl der Neukunden pro Monat zählen:
Code: Alles auswählen
select extract(month from erste_buchung) monat, count(adressnr) anzahl_neukunden
from (
select adressnr, min(belegdat) erste_buchung
from beleg
-- where belegtyp = 'V' and belegart = 'AU'
group by 1
having extract(year from min(belegdat)) = 2024)
group by 1
Für mein Beispiel hab ich die werksseitige Datumsfunktion extract benutzt und bin von folgender Tabellenstruktur ausgegangen, noch keine Indizes:
Code: Alles auswählen
create table beleg (
adressnr int,
belegtyp varchar(3),
belegart varchar(3),
belegdat date)
Falls die Spaltentypen nicht stimmen, speziell der Typ DATE von belegdat ist für diese Abfragen wichtig, und belegdat varchar ist, kann man die Abfragen entsprechend anpassen. Optimiert habe ich bei den Tests noch nicht, ich habe Tabelle beleg mit ca 1,1 Mio Sätzen gefüllt und für die letzte Abfrage Zeiten < 600 msek und mit der where-Bedingung aus Deinem Originalbeispiel < 300 msek. Klar, eine Belegtabelle kann auch 20 Mio Sätze haben - schau doch erstmal, wie die Abfrage bei Deinen Daten performt und dann gehts ggf ans Optimieren mittels Index, falls der where-Part nennenswert Sätze rausfiltert, zb:
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Do 15. Aug 2024, 08:42
von waldi969
WOW, danke für die ausführliche Antwort!!!
Ich habe die Zeit gemessen und bin auf 0,495 Sekunden, Perfekt. Ein Problem habe ich noch mit dem Ergebnis. Ich habe andere Werte als zuvor. Wahrscheinlich liegt es an der Abfrage nach dem Vertreter. Ist es für den Vertreter ein Neukunde oder für das Unternehmen. Ich werde es mal untersuchen und mich nochmals melden.
Super, vielen Dank!!!
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Do 15. Aug 2024, 10:08
von waldi969
Der Unterschied der Ergebnisse liegt, wie vermutet, an der Abfrage des Vertreters.
Ich muss den Vertreter im inneren Select eingrenzen, dann nimmt er natürlich den ersten Auftrag für diesen Vertreter Es ist nicht schlimm, und auch gut.
Alternativ wäre es schön, wenn ich es auch Unternehmensweit hätte. Also die Abfrage nach dem Vertreter und unternehmensweite Kunden. Wäre das möglich?
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Do 15. Aug 2024, 12:32
von bfuerchau
Das deutet eher auf ein Vernünftiges Werkzeug für Datenanalysen hin.
Denn solche Fragestellungen kannst du schöner und häufig auch einfacher mit z.B. Power-BI erreichen.
Am Anfang mag das gewöhnungsbedürftig sein, aber die Community ist groß.
Solange man bei Power-BI Desktop bleibt, ist das kostenlos.
Erst wenn man mehr will, kann das sehr schnell sehr teuer werden.
Dafür gibts dann andere, erheblich preiswertere, Lösungen.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Fr 16. Aug 2024, 08:23
von waldi969
Das Programm hatte ich auch schon probiert.
Ich bereite die Daten intern für andere Mitarbeiter auf. Somit ist Webseite mit API auf NodeJS Basis für mich der beste Weg, um regelmäßig gebrauchte Daten schnell für andere Mitarbeiter visuell aufzubereiten. Vielleicht ist es aber besser, nicht alles in SQL zu machen, sondern die Daten dann noch mit Javascript weiterzubearbeiten. Eine Liste, wo für alle Kundennummern das erste Auftragsdatum steht, kann dann weiter bearbeitet werden.
Vielen Dank für eure Hilfe und Zeit!
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Fr 16. Aug 2024, 11:09
von bfuerchau
Dann will ich dich nicht so auf dem Trockenen lassen:
with recursive dateRange as (
select cast('2024-01-01' as date) StartDate
,1 as StartMonth
from rdb$database
union all
select dateadd(1 month to StartDate)
, StartMonth + 1
from dateRange
where StartMonth < 12
)
,
DateFromTo as (
select StartDate
,dateadd(-1 day to dateadd(1 month to StartDate)) EndDate
from dateRange
)
select * from DateFromTo
Erklärungen:
Mit "With" kann man sog. derived Tables definieren. Hier kann man mehrere, durch Komma getrennte, Definitionen verwenden.
Dies entspricht dem Konstrukt
select * from (
select ...
) a
Nur dass man diese Definition dann mehrfach verwenden kann und nicht immer wiederholen muss. Desweiteren ist es übersichtlicher als derived Tables zu verschachteln
select * from (
select * from (
select * from
) b
) a
Mittels recursive definiert man, dass der select auf sich selbst zielt. Dies geht dann nur mit dem Union. Man muss eine Endebedingung definiere um die "Schleife" zu beenden.
Die Tiefe ist leider auf 1024 beschränkt. Überschreitet man dies, bricht der SQL ab.
Das obige Beispiel lässt sich dann per Join verbinden, z.B. als Pivot-Funktion
select
sum(case when extract(month from a."Leveldate") = 1 then 1 end) Count01
,sum(case when extract(month from a."Leveldate") = 2 then 1 end) Count02
-- usw.
,sum(case when extract(month from a."Leveldate") = 12 then 1 end) Count12
from DateFromTo
inner join "Umsatz View" a on a."Leveldate" between StartDate and Enddate
Mit diesem Beispiel werden je Monat die Anzahl der Belege gezählt.
Was Datumfunktionen angeht, schau dir die Firebirdreferenz online an:
DATEADD für Berechungen
EXTRACT mit Tag, Monat, Jahr ... zu entnehmen.
Diese Funktionen sind schneller als UDF's.
Viel Spaß.
Um allerdings Statistiken mit viel mehr Funktionen für den Betrieb bereitzustellen sind fertige und flexible Lösungen meist preiswerter da nichts mehr programmiert werden muss. Auch wenn man Ehda-Kosten nicht so ernst nimmt, aber man könnte die Zeit häufig sinnvoller verwenden.
Re: Gibt es die Möglichkeit einer Schleife?
Verfasst: Mo 19. Aug 2024, 03:21
von vr2
Der Unterschied der Ergebnisse liegt, wie vermutet, an der Abfrage des Vertreters.
Ich muss den Vertreter im inneren Select eingrenzen, dann nimmt er natürlich den ersten Auftrag für diesen Vertreter Es ist nicht schlimm, und auch gut.
Alternativ wäre es schön, wenn ich es auch Unternehmensweit hätte. Also die Abfrage nach dem Vertreter und unternehmensweite Kunden. Wäre das möglich?
Ja, nur hast Du es in diesem Fall mit zwei echt verschiedenen Mengen zu tun, in der Entstehung und Weiterverabeitung. Das würde ich auch in SQL so behandeln.
Vielleicht ist es aber besser, nicht alles in SQL zu machen, sondern die Daten dann noch mit Javascript weiterzubearbeiten
Grundsätzlich gibt es nichts leistungsfähigeres als SQL, um ernsthaft (also: für Erwachsene) auf Daten rumzukauen. Das musste selbst Google einsehen, als sie ihre NoSQL-Ansätze stillschweigend wieder einkassierten. Wenn Du in SQL fit bist, entsprechende Datenbank vorausgesetzt, und da ist Firebird keine schlechte Wahl, kriegst Du Abfragen und Datentransformationen hin, die in anderen Sprachen elend aufwändig bis nicht umsetzbar sind, von der Performance mal ganz abgesehen, das war ja Dein Ausgangspunkt, Abfragen über php-Schleife, klar performt das nicht. Javascript ist mittlerweile nicht übel, bietet eine ganze Menge, aber ist nicht die erste Wahl für Datentransformationen, der Schwerpunkt ist einfach ein anderer, wie bei allen normalen Programmiersprachen. Daran ändert auch nichts, dass es sehr gute js-libs gibt wie bspw d3 (
https://d3js.org/api) gibt, eine low-level-Visualisierungsbibliothek, die einige Funktionen aus der SQL-Welt versuchen in die javascript-Welt zu übertragen - weil sie dort gebraucht werden.
Ein anderer Ansatz ist das Bereitstellen von SQL-Engines als Web Assembly, so wie es bspw duckdb (
https://github.com/duckdb) macht, dann kannst Du SQL auch von javascript aus nutzen. Aber das Rumknatschen auf Daten passiert in SQL