SQL Abfrage Überschneidung von Bereichen

Michi

Benutzer
Beiträge
19
Hallo zusammen,
ich hab da ein Problem, mit dem ich nicht weiterkomme. Vieleicht kann mir ja jemand helfen?

Ich hab eine Tabelle, in die eingetragen wird, in welchem Zeitraum (von/bis) eine Währung gültig ist. Sollte es für eine Währung einen neuen Krus geben, darf sich der Gültigkeitszeitraum nicht überschneiden.

Beispieldaten:
ExRateIdvonbisWaehrungKurs
101.10.201823.01.2019AED4.400.000
224.01.201931.12.2021AED4.330.000
301.01.202215.10.2025AED4.200.000
416.10.202530.11.2026AED4.100.000
525.10.202630.07.2027AED4.100.000
In diesem Beispiel gibt es die Währung AED (sind in echt natürlich viele verschiedene) mit mehreren Zeiträumen in denen der jeweilige Kurs gilt bzw. gegolten hat.
Kommt jetzt ein neuer Kurs mit einem neuen Zeitraum dazu, darf sich dieser Zeitraum nicht mit einem für diese Währung bestehendem Zeitraum überschneiden.
Zeile 5 wäre hier z.B. falsch, das der 25.10.2026 ja schon in Zeile 4 enthalten ist, sich also überschneidet...
Ich tu mich gerade etwas schwer es besser zu erklären aber ich hoffe, man kann mein Problem nachvollziehen.
Ich würde das gerne entweder direkt bei der Eingabe checken, durch einen Tricker oder halt durch nur durch manuelles ausführen einer Abfrage.

Weis jemand wie ich das Abfragen kann? Es sind in der echten Tabelle natürlich viel mehr Datensätze und viele verschiedene Währungen. Verschiedene Währungen dürfen sich zeitlich auch überschneiden, nur nicht die gleiche Währung...
Vielen Dank schon mal an alle, die gewillt sind mir zu helfen :-)

Viele Grüße
Michi
 
Werbung:
Das könnte man sehr elegant lösen - allerdings mit PostgreSQL. Dort kannst Du einen sog. EXCLUSION CONSTRAINT definieren, der exakt das erzwingt (also daß sich da Zeiträume nicht überschneiden).

Ich mach mal ein Beispiel fertig, 10 Minuten ...
 
Zuletzt bearbeitet:
Code:
postgres=# create table michi (von_bis daterange, wahrung text default 'AED', kurs numeric, exclude using gist (wahrung with =, von_bis with &&));
CREATE TABLE
postgres=# 
postgres=# insert into michi (von_bis, kurs) values ('[2018-10-01,2019-01-23)',4.4);
INSERT 0 1
postgres=# insert into michi (von_bis, kurs) values ('[2019-01-24,2021-12-31)',4.3);
INSERT 0 1
postgres=# insert into michi (von_bis, kurs) values ('[2022-01-01,2025-10-15)',4.2);
INSERT 0 1
postgres=# insert into michi (von_bis, kurs) values ('[2025-10-16,2026-11-30)',4.1);
INSERT 0 1
postgres=# insert into michi (von_bis, kurs) values ('[2026-10-25,2027-07-30)',4.1);
ERROR:  conflicting key value violates exclusion constraint "michi_wahrung_von_bis_excl"
DETAIL:  Key (wahrung, von_bis)=(AED, [2026-10-25,2027-07-30)) conflicts with existing key (wahrung, von_bis)=(AED, [2025-10-16,2026-11-30)).
postgres=#
 
vielleicht noch zur Erklärung: der Constraint ist durch einen Index realisiert, der exakt das prüft:

Code:
postgres=# \d michi
                   Table "public.michi"
 Column  |   Type    | Collation | Nullable |   Default   
---------+-----------+-----------+----------+-------------
 von_bis | daterange |           |          | 
 wahrung | text      |           |          | 'AED'::text
 kurs    | numeric   |           |          | 
Indexes:
    "michi_wahrung_von_bis_excl" EXCLUDE USING gist (wahrung WITH =, von_bis WITH &&)

postgres=#

Also, es wird geprüft, daß "wahrung WITH =" (also Waehrung gleich ist) und "von_bis WITH &&" sich überlappt (&& ist der Überlappungsoperator).
Dadurch, daß das indexbasiert ist, geht das auch bei Millionen oder mehr Datensätzen irre schnell.
 
Das gehört natürlich in die Applikation. Selbst der Exclusion Constraint nützt dir da nix. Die Fehlermeldung, die da ausgeworfen wird musst du eh in deiner Applikation abhandeln.
 
Das gehört natürlich in die Applikation. Selbst der Exclusion Constraint nützt dir da nix. Die Fehlermeldung, die da ausgeworfen wird musst du eh in deiner Applikation abhandeln.
Da kann (und sollte) man auch machen, um nette Fehlermeldungen anzeigen zu können.

Aber um sicherzustellen, dass nur valide Daten in der Datenbank landen, sollte man alles was man deklarativ als Constraint definieren kann, auch in der Datenbank absichern.

Typischerweise leben Datenbanken (und deren Daten) deutlich länger als die Anwendungen die darauf zugreifen. Ausserdem gibt es meistens nicht nur eine Anwendung die darauf zugreift. Z.B. willst Du auch verhindern, dass ein Batch-Job der in der Nach Daten importiert invalide Daten einfügt.
 
Selbst der Exclusion Constraint nützt dir da nix. Die Fehlermeldung, die da ausgeworfen wird musst du eh in deiner Applikation abhandeln.
Oh doch! Er nützt sehr viel, erst Recht, wenn er dabei nicht merklich Resourcen kostet. Das ist Datenkonsistenz.
Datenkonsistenz ist ein wesentlicher Existenz- und Berechtigungsgrund für RDBMS.

In der Anwendung kannst Du natürlich machen was Du willst, Datenvalidierung, Fehlervermeidung und sogar Fehlerbehandlung.
 
Oh doch! Er nützt sehr viel, erst Recht, wenn er dabei nicht merklich Resourcen kostet. Das ist Datenkonsistenz.
Datenkonsistenz ist ein wesentlicher Existenz- und Berechtigungsgrund für RDBMS.

In der Anwendung kannst Du natürlich machen was Du willst, Datenvalidierung, Fehlervermeidung und sogar Fehlerbehandlung.
Niemand verbietet ja, vor dem Insert zu prüfen:

Code:
postgres=# select * from michi where wahrung = 'AED' and von_bis && '[2026-10-25,2027-07-30)';
         von_bis         | wahrung | kurs 
-------------------------+---------+------
 [2025-10-16,2026-11-30) | AED     |  4.1
(1 row)

Das kann man in der Applikation VOR dem Insert machen. Und auch, wenn da kein Datensatz kommt, immer noch den Erfolg des Inserts prüfen.
 
Werbung:
Zurück
Oben