SQL Query gesucht: "dynamische" Summe

Schachigel

Benutzer
Beiträge
13
Ich habe Window Functions und subQueries versucht - aber bei mir hat es nicht geklappt. Vlt kann hier jemand helfen:

Hier mein Problem:
In einer Tabelle, die Verkäufe von Produkten repräsentiert, gäbe es 3 Spalten: ArtikleNr, VerkDatum, Wert
Jeder Datensatz entspricht also einem Verkauf eines Artikels zu einem best. Datum zu einem best. Preis.

Jetzt suche ich ein SQL Statement, dass daraus eine neue Tabelle erzeugt:
VerkDatum | ArtikelNr | <Summer der Werte aller im Jahr vor VerkDatum verkauften Artikeln der Artikel Nr.>

Das schwierige dabei ist, dass die Zeitspanne, über die summiert werden soll, von VerkDatum abhängt (also Date(VerkDatum, '-1 years'). Klingt nicht so schwierig - aber ich hab es nicht geschafft. Hat einer eine Idee, einen Hinweis?
Danke fürs lesen!
 
Werbung:
so in etwa?
Code:
create table artikel(nummer integer, verkdatum date, wert numeric);
insert into artikel values (1, now()::date-1, '100');
insert into artikel values (1, now()::date-1, '100');
insert into artikel values (1, now()::date-1, '100');
insert into artikel values (1, now()::date, '100');
select sum(wert) from artikel where verkdatum >= now()::date-'1 years'::interval group by artikel;

Resultat:
300
100
 
ich bin mir nicht sicher, ob ich die Frage richtig verstanden habe. Du hast z.B.:

Code:
edb=*# select * from schachigel;
 id |     verkdatum      | artikel | wert 
----+--------------------+---------+------
  1 | 01-JAN-21 00:00:00 |       1 |  100
  2 | 01-FEB-21 00:00:00 |       1 |  200
  3 | 03-JAN-22 00:00:00 |       1 |  300
  4 | 01-MAR-21 00:00:00 |       2 | 1000
  5 | 01-JAN-22 00:00:00 |       2 | 2000
  6 | 01-APR-21 00:00:00 |       1 |  250
(6 rows)

und willst nun immer vom verkdatum ausgehend alles, was zwischen verdatum und verdatum-1Jahr ist als Summe gruppieren. Das wären dann mal so als Zwischentabelle diese Datensätze (jetzt noch nicht gruppiert, aber je id sind zu beachten:

Code:
edb=*# select s1.id, s1.verkdatum, s1.artikel, s1.wert, x.wert from schachigel s1 left join lateral (select * from schachigel s2 where s2.verkdatum between s1.verkdatum - '1year'::interval and s1.verkdatum and s1.artikel=s2.artikel and s1.id != s2.id) x on (true);
 id |     verkdatum      | artikel | wert | wert 
----+--------------------+---------+------+------
  1 | 01-JAN-21 00:00:00 |       1 |  100 |     
  2 | 01-FEB-21 00:00:00 |       1 |  200 |  100
  3 | 03-JAN-22 00:00:00 |       1 |  300 |  200
  3 | 03-JAN-22 00:00:00 |       1 |  300 |  250
  6 | 01-APR-21 00:00:00 |       1 |  250 |  100
  6 | 01-APR-21 00:00:00 |       1 |  250 |  200
  4 | 01-MAR-21 00:00:00 |       2 | 1000 |     
  5 | 01-JAN-22 00:00:00 |       2 | 2000 | 1000
(8 rows)

edb=*#

Stimmt das soweit?
(als Zwischenergebniss, jetzt noch je id und Artikel die 2 wert-Spalten passend addieren, trivial nun)

Falls ja: ich nutze dazu einen LATERAL JOIN, der zwar als SQL-Standard definiert ist, aber kaum in real existierenden Datenbanken realisiert ist. Vermutlich auch nicht in SQLite.
 
Hallo und danke für die Antworten!
@Kampfgummibaerlie: ich hab mit dem sqlite-brower versucht das nach zu vollziehen. Aber leider ging das nicht. Das Konstrukt now()::date-1 gibt es wohl nicht. Ich vermute now()::date ist analog zu date('now')? Bedeutet dann -1 der Tag davor? oder das Jahr?
Auf jeden Fall: Das Jahr sollte immer relativ zum Datum des Kaufs sein, nicht relativ zu heute. Ich glaube das wird von Deiner Query nicht so gemacht.

@akretschmer: den Lateral join gibt es tatsächlich nicht in SqLite :( - aber es hat mal einer eine Masterarbeit darüber geschrieben, wie man ihn einbauen könnte ( :) hätte er es doch getan ;))
Aber wie Du beschreibst, was ich möchte: ja - ich glaube das ist es fast. Wobei ich das Jahr ohne den ersten und incl. des Kaufdatums machen möchte. Dann sähe Dein Beispiel wohl so aus:

Code:
  1 | 01-JAN-21 00:00:00 |       1 |  100 |  100
  2 | 01-FEB-21 00:00:00 |       1 |  200 |  300
  3 | 01-MAR-21 00:00:00 |       2 | 1000 | 1000
  4 | 01-APR-21 00:00:00 |       1 |  250 |  550
  5 | 01-JAN-22 00:00:00 |       2 | 2000 | 3000
  6 | 03-JAN-22 00:00:00 |       1 |  300 |  750

Zeile 1: nur der Kauf selbst
Zeile 2: zwei käufe im letzten Jahr
Zeile 3: erster Kauf anderes Produkt
Zeile 4: 3 Käufe von Produkt 1
Zeile 5: 2 Produkte vom Typ 2
Zeile 6: Der Wert von Zeile 1 entfällt, da mehr als 1 Jahr her

Kriegt man das auch ohne Lateral Join hin?
 
Werbung:
Juhu - nach einigem "Fummeln" habe ich es raus. Am Ende hing es daran, dass man in der subquery, die sich auf die selbe Ausgangstabelle bezieht, der Tabelle einen alias "verpasst".

Hier mein "Kunstwerk":

INPUT
Code:
#   verkDatum    wert
1    2021-01-01     100
1    2021-02-01     200
2    2021-03-01    1000
1    2021-04-01     250
2    2022-01-01    2000
1    2022-01-01      33
1    2022-01-03     300


Code:
SELECT artikel.nummer
, artikel.verkdatum
, artikel.wert
, (SELECT sum(wert)
   FROM (
     SELECT wert
     FROM artikel as refA
     WHERE refA.nummer = artikel.nummer
        AND refA.verkdatum > DATE(artikel.verkDatum, '-1 years')
        AND refA.verkdatum  <= artikel.verkdatum
        )
  ) AS summe   
FROM artikel
GROUP BY verkdatum, nummer

OUTPUT
Code:
1    2021-01-01     100    100
1    2021-02-01     200    300
2    2021-03-01    1000   1000
1    2021-04-01     250    550
1    2022-01-01      33    483
2    2022-01-01    2000   3000
1    2022-01-03     300    783

Mit dem zweiten Argument bei der "Group by" clause funktioniert es auch, wenn es mehrere Buchungen am gleichen Tag gibt.
Prima - nochmals danke für Eure Anregungen. War dann leichter als gedacht... wie das so ist.
 
Zurück
Oben