Update howto-fhir-date-parameter.md
This commit is contained in:
+110
-21
@@ -52,23 +52,110 @@ Treffer-Bereich (grün/farbig schattiert):
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `eq` | gleich | Resource-Intervall liegt vollständig im Such-Intervall |
|
| `eq` | gleich | Resource-Intervall liegt vollständig im Such-Intervall |
|
||||||
| `ne` | ungleich | Komplement von `eq` |
|
| `ne` | ungleich | Komplement von `eq` |
|
||||||
| `gt` | größer als | Resource-Datum beginnt nach dem Ende des Such-Intervalls |
|
| `gt` | größer als | Resource-Intervall **ragt über** das Ende des Such-Intervalls hinaus |
|
||||||
| `lt` | kleiner als | Resource-Datum endet vor dem Beginn des Such-Intervalls |
|
| `lt` | kleiner als | Resource-Intervall **beginnt vor** dem Anfang des Such-Intervalls |
|
||||||
| `ge` | größer/gleich | Beginnt am oder nach Beginn des Such-Intervalls |
|
| `ge` | größer/gleich | `gt` **oder** vollständig im Such-Intervall enthalten (`eq`) |
|
||||||
| `le` | kleiner/gleich | Endet am oder vor Ende des Such-Intervalls |
|
| `le` | kleiner/gleich | `lt` **oder** vollständig im Such-Intervall enthalten (`eq`) |
|
||||||
| `sa` | starts after | Beginnt vollständig **nach** dem Ende des Such-Intervalls |
|
| `sa` | starts after | Beginnt vollständig **nach** dem Ende des Such-Intervalls, keine Überlappung |
|
||||||
| `eb` | ends before | Endet vollständig **vor** dem Beginn des Such-Intervalls |
|
| `eb` | ends before | Endet vollständig **vor** dem Beginn des Such-Intervalls, keine Überlappung |
|
||||||
| `ap` | approximately | Ungefähre Übereinstimmung, Toleranz serverabhängig |
|
| `ap` | approximately | Überlappung, plus ähnliche Größenordnung der Intervalle |
|
||||||
|
|
||||||
**Praxis-Tipp:** `sa`/`eb` unterscheiden sich von `gt`/`lt` nur spürbar bei
|
**Wichtig — Containment vs. Overlap:** Nur `eq` (und implizit `sa`/`eb`)
|
||||||
Resource-Feldern, die selbst ein **Intervall** sind (`Period`, z. B.
|
verlangen, dass das Resource-Intervall **vollständig** innerhalb bzw.
|
||||||
`Encounter.period`). Bei einem einzelnen Zeitpunkt-Feld ist der Unterschied
|
**vollständig getrennt** vom Such-Intervall liegt. Bei `gt`, `lt`, `ge`
|
||||||
meist nicht beobachtbar – `gt` reicht schon, wenn die Period *beginnt* nach
|
und `le` reicht dagegen eine **Überlappung** — das Resource-Intervall muss
|
||||||
dem Suchdatum; `sa` verlangt, dass die *gesamte* Period danach liegt.
|
nicht komplett außerhalb des Suchbereichs liegen, es genügt, dass es über
|
||||||
|
die jeweilige Grenze hinausragt. Details dazu im nächsten Abschnitt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Mehrere `date`-Parameter kombinieren
|
## 3. Sonderfall: Matching gegen `Period` und `Range`
|
||||||
|
|
||||||
|
Die Grafiken oben zeigen das Resource-Datum als schmalen roten Marker – das
|
||||||
|
passt für einfache `date`/`dateTime`-Felder wie `Patient.birthDate`. Sobald
|
||||||
|
das Zielfeld selbst ein **Intervall** ist (`Period`, z. B.
|
||||||
|
`Encounter.period`, `Condition.onsetPeriod`, oder `Range`), wird die
|
||||||
|
Unterscheidung zwischen **Containment** (vollständiges Enthaltensein) und
|
||||||
|
**Overlap** (bloße Überlappung) entscheidend:
|
||||||
|
|
||||||
|
- **`eq`** verlangt Containment: das gesamte Resource-Intervall muss im
|
||||||
|
Such-Intervall liegen.
|
||||||
|
- **`gt` / `lt` / `ge` / `le`** verlangen nur Overlap: es reicht, wenn das
|
||||||
|
Resource-Intervall über die jeweilige Grenze hinausragt – auch wenn ein
|
||||||
|
Teil davon auf der "falschen" Seite liegt.
|
||||||
|
- **`sa` / `eb`** verlangen das Gegenteil von Overlap: das Resource-Intervall
|
||||||
|
muss vollständig und ohne jede Überlappung auf der jeweiligen Seite liegen.
|
||||||
|
|
||||||
|
**Beispiel:** Ein Encounter läuft vom 10. bis 20. Juni. Die Suche
|
||||||
|
`date=gt2023-06-15` soll ihn finden, obwohl der Encounter *vor* dem 15.
|
||||||
|
begonnen hat — entscheidend ist nur, dass er über den 15. hinausreicht
|
||||||
|
(Overlap mit dem Bereich "nach dem 15."). Bei `date=sa2023-06-15` würde
|
||||||
|
derselbe Encounter dagegen **nicht** matchen, weil er nicht vollständig nach
|
||||||
|
dem 15. liegt — genau das ist der praktische Unterschied zwischen `gt` und
|
||||||
|
`sa`.
|
||||||
|
|
||||||
|
Die folgende Grafik macht das für alle vier "einseitigen" Präfixe (`gt`,
|
||||||
|
`sa`, `lt`, `eb`) an denselben drei Beispiel-Periods sichtbar — einer
|
||||||
|
Period komplett davor, einer, die die Suchgrenze überlappt, und einer
|
||||||
|
komplett danach:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Man sieht deutlich: `gt` und `lt` (blau schattierter Bereich, durchgezogene
|
||||||
|
Grenzlinie) lassen die überlappende Period B als Treffer durch, während `sa`
|
||||||
|
und `eb` (gestrichelte Grenzlinie) sie ablehnen — nur eine Period, die
|
||||||
|
komplett auf der richtigen Seite liegt, zählt dort.
|
||||||
|
|
||||||
|
| Encounter-Zeitraum | `date=gt2023-06-15` | `date=sa2023-06-15` |
|
||||||
|
|---|---|---|
|
||||||
|
| 10.–20. Juni (überlappt die Grenze) | ✅ Treffer (Overlap) | ❌ kein Treffer (nicht vollständig danach) |
|
||||||
|
| 16.–20. Juni (komplett danach) | ✅ Treffer | ✅ Treffer |
|
||||||
|
| 01.–10. Juni (komplett davor) | ❌ kein Treffer | ❌ kein Treffer |
|
||||||
|
|
||||||
|
### Offene (unvollständige) Periods
|
||||||
|
|
||||||
|
In der Praxis sind Periods oft **nicht abgeschlossen** — z. B. ein laufender
|
||||||
|
Encounter ohne `end`, oder ein importierter Datensatz mit unbekanntem
|
||||||
|
`start`. Der FHIR-Standard regelt das eindeutig:
|
||||||
|
|
||||||
|
> Ein fehlender unterer Rand (`start`) gilt implizit als **kleiner als jedes
|
||||||
|
> reale Datum** (also `-∞`). Ein fehlender oberer Rand (`end`) gilt implizit
|
||||||
|
> als **größer als jedes reale Datum** (also `+∞`).
|
||||||
|
|
||||||
|
Das hat spürbare Konsequenzen, gerade für `sa` und `eb`:
|
||||||
|
|
||||||
|
- Ein laufender Encounter (`start` gesetzt, `end` fehlt → `end = +∞`)
|
||||||
|
kann **niemals** `eb` (ends before) matchen — sein Ende liegt ja nie vor
|
||||||
|
irgendeinem endlichen Datum. Er matcht aber sehr wohl `gt`, weil sein
|
||||||
|
(unendliches) Ende immer über jede Suchgrenze hinausragt.
|
||||||
|
- Ein Encounter mit unbekanntem Start (`start` fehlt → `start = -∞`) kann
|
||||||
|
**niemals** `sa` (starts after) matchen — sein Beginn liegt ja nie nach
|
||||||
|
irgendeinem endlichen Datum. Er matcht aber `lt`, weil sein (unendlicher)
|
||||||
|
Anfang immer vor jede Suchgrenze hineinreicht.
|
||||||
|
- Eine Period ganz ohne `start` und `end` überlappt praktisch **jeden**
|
||||||
|
overlap-basierten Filter (`gt`, `lt`, `ge`, `le`) — sie „reicht" ja per
|
||||||
|
Definition über jede Grenze hinaus.
|
||||||
|
|
||||||
|
Dieselben vier Präfixe wie oben, jetzt mit offenen statt geschlossenen
|
||||||
|
Periods:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Praktische Konsequenz:** Wenn du „laufende" Ressourcen (z. B. aktive
|
||||||
|
Encounter, offene Verordnungen) gezielt aus einer Zeitraumsuche ausschließen
|
||||||
|
willst, reicht `eb`/`sa` allein nicht — du musst zusätzlich nach dem Status
|
||||||
|
oder explizit nach `end:missing=true`/`start:missing=true` filtern, je
|
||||||
|
nachdem, was dein Server unterstützt.
|
||||||
|
|
||||||
|
Bei einem einfachen Zeitpunkt-Feld (kein `Period`) fällt dieser Unterschied
|
||||||
|
praktisch nicht auf, da Resource-Start und -Ende (fast) identisch sind — dort
|
||||||
|
verhalten sich `gt` und `sa` de facto gleich. Der Unterschied wird erst bei
|
||||||
|
echten Zeitspannen relevant. Das ist auch der Grund, warum `sa`/`eb`
|
||||||
|
laut Spezifikation in erster Linie für `Period`/`Range`-Werte gedacht sind.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Mehrere `date`-Parameter kombinieren
|
||||||
|
|
||||||
In der Praxis reicht ein einzelner Präfix selten – meist willst du einen
|
In der Praxis reicht ein einzelner Präfix selten – meist willst du einen
|
||||||
**Bereich** definieren. FHIR-Server verknüpfen mehrere `date`-Parameter in
|
**Bereich** definieren. FHIR-Server verknüpfen mehrere `date`-Parameter in
|
||||||
@@ -89,7 +176,7 @@ klassischen Zeitfenster-Queries in SQL.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Die vollständige 3×3-Matrix aller Bereichs-Kombinationen
|
## 5. Die vollständige 3×3-Matrix aller Bereichs-Kombinationen
|
||||||
|
|
||||||
Die vier Muster oben sind nur die gebräuchlichsten. Tatsächlich lässt sich
|
Die vier Muster oben sind nur die gebräuchlichsten. Tatsächlich lässt sich
|
||||||
**jede** Untergrenze mit **jeder** Obergrenze kombinieren:
|
**jede** Untergrenze mit **jeder** Obergrenze kombinieren:
|
||||||
@@ -110,7 +197,7 @@ gültige, funktionierende Query.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Sonderfälle: Wenn Kombinationen redundant oder widersprüchlich werden
|
## 6. Sonderfälle: Wenn Kombinationen redundant oder widersprüchlich werden
|
||||||
|
|
||||||
Nicht jede syntaktisch gültige Kombination ist auch praktisch sinnvoll. Drei
|
Nicht jede syntaktisch gültige Kombination ist auch praktisch sinnvoll. Drei
|
||||||
Kategorien solltest du kennen, bevor du sie versehentlich in einer
|
Kategorien solltest du kennen, bevor du sie versehentlich in einer
|
||||||
@@ -146,19 +233,21 @@ Rückmeldung. Es lohnt sich, so etwas clientseitig vorab zu validieren.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Praxis-Empfehlungen zum Schluss
|
## 7. Praxis-Empfehlungen zum Schluss
|
||||||
|
|
||||||
- Für einfache Bereichsfilter ist **`ge` + `lt`** (halboffenes Intervall) meist
|
- Für einfache Bereichsfilter ist **`ge` + `lt`** (halboffenes Intervall) meist
|
||||||
das robusteste Muster – es vermeidet Rundungsprobleme an der
|
das robusteste Muster – es vermeidet Rundungsprobleme an der
|
||||||
Precision-Grenze (kein Off-by-one bei „bis einschließlich 31.12.").
|
Precision-Grenze (kein Off-by-one bei „bis einschließlich 31.12.").
|
||||||
- **`sa`/`eb`** nur einsetzen, wenn das Zielfeld tatsächlich ein `Period`- oder
|
- **`sa`/`eb`** bewusst einsetzen, wenn du bei `Period`/`Range`-Feldern eine
|
||||||
`Range`-Element ist. Bei einfachen `date`/`dateTime`-Feldern liefern sie in
|
*vollständige* Trennung brauchst (siehe Abschnitt 3) – z. B. „Encounter
|
||||||
der Regel dasselbe Ergebnis wie `gt`/`lt` – der zusätzliche Ausdruck bringt
|
vollständig nach Entlassung X". Für einen simplen „ab Datum X"-Filter ist
|
||||||
dann keinen Mehrwert.
|
meist `ge`/`gt` gemeint, nicht `sa`.
|
||||||
- Vor dem Absetzen einer Multi-Parameter-Query lohnt sich ein kurzer Check auf
|
- Vor dem Absetzen einer Multi-Parameter-Query lohnt sich ein kurzer Check auf
|
||||||
logische Konsistenz zwischen Unter- und Obergrenze, um leere Ergebnisse
|
logische Konsistenz zwischen Unter- und Obergrenze, um leere Ergebnisse
|
||||||
durch Konfigurationsfehler in der eigenen Pipeline zu vermeiden.
|
durch Konfigurationsfehler in der eigenen Pipeline zu vermeiden.
|
||||||
|
|
||||||
Mit diesen fünf Grafiken im Hinterkopf – ohne Präfix, alle neun Präfixe
|
Mit diesen fünf Grafiken im Hinterkopf – ohne Präfix, alle neun Präfixe
|
||||||
einzeln, typische Kombinationen, die volle 3×3-Matrix und die Sonderfälle –
|
einzeln, typische Kombinationen, die volle 3×3-Matrix und die Sonderfälle –
|
||||||
sollte die nächste `date`-Query im FHIR-Suchparameter kein Rätsel mehr sein.
|
und dem Wissen um den Unterschied zwischen Containment und Overlap bei
|
||||||
|
`Period`/`Range`-Feldern sollte die nächste `date`-Query im
|
||||||
|
FHIR-Suchparameter kein Rätsel mehr sein.
|
||||||
|
|||||||
Reference in New Issue
Block a user