---
{
  "title": "Da Vinci PAS-Metriken mit SQL on FHIR in Aidbox",
  "description": "Berechnung der operativen Da Vinci PAS-Metriken mit SQL on FHIR in Aidbox.",
  "date": "2026-06-16",
  "author": "Akim Khalitov",
  "reading-time": "5 minutes",
  "tags": [
    "Analytics",
    "SQL on FHIR",
    "Prior Authorization"
  ],
  "tldr": "Der Artikel zeigt, wie CMS-0057-relevante operative Da Vinci PAS-Metriken direkt auf FHIR-Daten zur Vorabgenehmigung mithilfe von SQL on FHIR berechnet werden können – ohne ein separates Data Warehouse aufzubauen. Er stellt die SQL on FHIR-Werkzeuge, ViewDefinitions, SQLViews und SQLQueries vor und zeigt, wie wenig Aufwand es bedarf, diese Artefakte zu erstellen, zu paketieren und anschließend zu materialisieren und in BI-Tools wie Metabase, Tableau oder Power BI einzuspeisen."
}
---
Prior Authorization ist ein anhaltender Reibungspunkt im US-amerikanischen Gesundheitswesen, und der
Druck, sie zu messen, wächst stetig: Kostenträger möchten sehen, wo es stockt, und
die entsprechende Berichterstattung ist auf dem Weg, eine regulatorische Anforderung zu werden. Das bedeutet,
Einreichungsvolumen, Fehlerquote und Zeit bis zur Entscheidung zu messen.

Das [Da Vinci PAS IG](https://hl7.org/fhir/us/davinci-pas/) benennt
[zehn operative Metriken](https://build.fhir.org/ig/HL7/davinci-pas/metrics.html)
und enthält ein
[`PASMetricData`](https://build.fhir.org/ig/HL7/davinci-pas/StructureDefinition-PASMetricData.html)-Logikmodell,
das die Datenbasis für die Metriken beschreibt.

Deren Berechnung erfordert üblicherweise, die Daten in ein separates Analysesystem zu kopieren und
jede Metrik dort neu zu implementieren – eine Eigenentwicklung, die an jeder Stelle wiederholt wird und
von der Quelle abweicht. Wir wollten das Gegenteil: jede Metrik einmal definieren, direkt neben den
Daten ausführen und mit den bereits vorhandenen BI-Tools lesen. Da die Transformation deklarativ ist und
in der Datenbank verbleibt, wird nichts ausgelagert, was synchron gehalten werden müsste, und es muss
kein zweiter Analytics-Stack aufgebaut werden. Aidbox bot dafür bereits eine Lösung:
das integrierte [SQL on FHIR](https://sql-on-fhir.org/ig/).

## SQL on FHIR in einer Minute

[SQL on FHIR](https://sql-on-fhir.org/ig/) standardisiert sowohl die Abflachung als auch die
Abfragen darüber, anstatt dass jeder Anbieter seinen eigenen Weg zur Abfrage verschachtelter
Ressourcen erfindet. Ihre Metriken werden zu portablen, standardisierten FHIR-Artefakten – interoperable Analytics,
[hier ausführlich erklärt](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics).
Die Bausteine:

1. **[ViewDefinition](https://sql-on-fhir.org/ig/StructureDefinition-ViewDefinition.html)**:
   ein portables Format zur Definition tabellarischer Sichten auf FHIR-Daten.
2. **[SQLQuery](https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/StructureDefinition-SQLQuery.html)**
   und **SQLView**: teilbares SQL über diese Sichten, basierend auf der FHIR-
   [Library](https://hl7.org/fhir/R5/library.html)-Ressource. Eine SQLQuery akzeptiert
   Parameter, beispielsweise einen Berichtszeitraum; eine SQLView ist parameterlos.
3. **[HTTP API](https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/index.html#http-api)**:
   Standard-FHIR-Operationen (`$viewdefinition-run`, `$sqlquery-run`) zur Ausführung von Sichten
   und Abfragen.

Aidbox führt all dies gegen dieselbe Postgres-Instanz aus, die auch die Live-FHIR-API unterstützt, sodass
Daten und Analytics in einer einzigen Datenbank liegen.

## Fünf Schichten – von rohen FHIR-Daten bis zum Dashboard

PAS-Daten sind schwierig zu glätten. Sie sind X12-abgeleitet, mit Antworten, die über
mehrere Zyklen eintreffen, und Metriken, die sich über Claim, ClaimResponse sowie den beteiligten
Leistungserbringer und die Versicherungsdeckung erstrecken. Keine einzelne Sicht
liefert eine Metrikzeile; daher ist die Pipeline in Schichten aufgebaut, wobei jede die
darunter liegende liest – und der Graph dieser Schichten ist die Herkunftskette (Lineage).

Das Stapeln flacher Sichten zu einem gemeinsamen Modell und anschließend das Aufsetzen von Metriken darüber
ist das allgemeine Analytics-Muster, das in
[SQL on FHIR: Interoperable Analytics](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics)
ausführlich beschrieben wird; hier wenden wir es auf PAS an:

<div class="narrow" style="display: flex; justify-content: center">

```mermaid
flowchart TD
  L1["Layer 1: Raw FHIR<br/>Claim, ClaimResponse, Practitioner, Coverage"]
  L2["Layer 2: ViewDefinitions<br/>flatten each resource into a table"]
  L3["Layer 3: SQLViews<br/>cross-resource joins"]
  L4["Layer 4: Metric model<br/>PASMetricDataView"]
  L5["Layer 5: Metric queries<br/>one SQLQuery per metric"]
  BI["Any BI tool / dashboard"]
  L1 --> L2 --> L3 --> L4 --> L5 --> BI
```

</div>

Das IG definiert zehn Metriken:

<div class="narrow">

| Metrik | Was sie misst |
|--------|---------------|
| 1. Einreichungsvolumen | Volumen der PAS-Einreichungen (als 278 und Einzelpositionen) |
| 2. Aktualisierungen, Stornierungen, Anfragen | Volumen der PAS-Aktualisierungen, -Stornierungen und -Anfragen |
| 3. Anfragen durch andere Leistungserbringer | Volumen der Anfragen durch andere als den verordnenden Leistungserbringer |
| 4. Fehlerquote | Anteil der PAS-Einreichungen, die einen Fehler zurückgeben (nach Typ und Kostenträger) |
| 5. Abschluss bei Ersteinreichung | Anteil der PAS-Einreichungen, die bei der Ersteinreichung ein abschließendes Ergebnis zurückgeben (für einzelne und alle Positionen) |
| 6. PEND-Volumen und Auflösung | Volumen der Einzelpositionen mit einem initialen PEND sowie Anzahl der aufgelösten PENDs und (komplexer) durchschnittliche Zeit zur Auflösung jedes PENDs |
| 7. Zeit bis zum abschließenden Ergebnis | Gesamtzeit von der Ersteinreichung bis zum abschließenden PA-Ergebnis für alle Einzelpositionen |
| 8. Segmentierung | Alle oben genannten Metriken aufgeschlüsselt nach Kostenträger / Leistungserbringer (je nach Metrik) und im Zeitverlauf |
| 9. offene Anfragen | Offene PAS-Anfragen |
| 10. PEND-Alterung | Alterung ausstehender PEND-Anfragen |

</div>

Wir werden die erste Metrik, das Einreichungsvolumen, durchgehen, da sie die unkomplizierteste ist. Wir
verfolgen sie Schicht für Schicht, beginnend bei Schicht 1, den rohen Ressourcen.

**Schicht 1:** Nehmen wir zwei Vorabgenehmigungsansprüche (Preauthorization Claims), `c1` mit zwei Einzelpositionen und `c2` mit
einer. Hier ist `c1` als verschachteltes JSON:

```json
{
  "resourceType": "Claim",
  "use": "preauthorization",
  "created": "2026-02-01",
  "provider": { "reference": "Practitioner/p1" },
  "item": [ { "sequence": 1, ... }, { "sequence": 2, ... } ]
}
```

**Schicht 2:** Eine ViewDefinition übernimmt die Abflachung. Eine `where`-Bedingung filtert die Vorabgenehmigungsansprüche, und
`forEach` über `item` wandelt das Array in eine Zeile pro Position um. Jede Spalte ist ein FHIRPath-
Ausdruck: `getResourceKey()` und `getReferenceKey()` für IDs und Referenzen, gewöhnliche
Pfade für den Rest – selbst Werte, die tief in PAS-Erweiterungen verborgen sind, ohne benutzerdefiniertes Parsen:

```json
{
  "resourceType": "ViewDefinition",
  "name": "ClaimView",
  "resource": "Claim",
  "where": [{ "path": "use = 'preauthorization'" }],
  "select": [
    { "column": [
      { "name": "claim",    "path": "getResourceKey()" },
      { "name": "created",  "path": "created" },
      { "name": "provider", "path": "provider.getReferenceKey()" }
    ]},
    { "forEach": "item", "column": [{ "name": "item", "path": "sequence" }] }
  ]
}
```

Über beide Ansprüche hinweg ergibt das eine Zeile pro Position:

<div class="narrow">

| claim | created    | provider | item |
|-------|------------|----------|------|
| c1    | 2026-02-01 | p1       | 1    |
| c1    | 2026-02-01 | p1       | 2    |
| c2    | 2026-02-01 | p1       | 1    |

</div>

**Schicht 3:** Eine SQLView, `ClaimWithProviderView`, verbindet `ClaimView` mit `PractitionerView`,
um die NPI des Leistungserbringers hinzuzufügen:

```sql
-- depends on: ClaimView, PractitionerView
select c.*, pr.npi as provider_npi
from "ClaimView" c
left join "PractitionerView" pr on pr.id = c.provider
```

was folgendes ergibt:

<div class="narrow">

| claim | created    | provider | item | provider_npi |
|-------|------------|----------|------|--------------|
| c1    | 2026-02-01 | p1       | 1    | 199...       |
| c1    | 2026-02-01 | p1       | 2    | 199...       |
| c2    | 2026-02-01 | p1       | 1    | 199...       |

</div>

**Schicht 4:** das Modell.

Die Antwortseite, `ResponseResultView`, wird analog zur Anspruchsseite aufgebaut: Eine ViewDefinition
glättet jedes `ClaimResponse`-Element, und eine SQLView macht dessen `claim`, `item` und `result` zugänglich.
`PASMetricDataView` verbindet jede Anspruchsposition per Left Join mit ihrer Antwort, sodass jede Zeile
sowohl die Anfrage als auch deren Ergebnis enthält – das PASMetricData-Modell, hier als eine Zeile pro
Einzelposition realisiert:

```sql
-- depends on: ClaimWithProviderView, ResponseResultView
select c.claim   as exchange_id,
       c.item    as item_sequence,
       c.created as request_time,
       r.result
from "ClaimWithProviderView" c
left join "ResponseResultView" r
  on r.claim = c.claim and r.item = c.item
```

was das gemeinsame Modell liefert, gegen das jede Metrik ausgeführt wird:

<div class="narrow">

| exchange_id | item_sequence | request_time | result   |
|-------------|---------------|--------------|----------|
| c1          | 1             | 2026-02-01   | approved |
| c1          | 2             | 2026-02-01   | pended   |
| c2          | 1             | 2026-02-01   | approved |

</div>

**Schicht 5:** Das Einreichungsvolumen ist eine Aggregation über dieses Modell, eine SQLQuery. Sie ist
eine Adoptionsmetrik und zählt daher Einreichungen und Positionen pro Berichtsjahr, das
ein Dashboard nach Bedarf filtern kann:

```sql
-- SubmissionVolume, by reporting year
-- depends on: PASMetricDataView
select extract(year from request_time)::int as reporting_year,
       count(distinct exchange_id) as submission_count,
       count(*) as service_item_count
from "PASMetricDataView"
group by reporting_year
```

Als SQLQuery-Ressource trägt sie eine kanonische URL, ihre `depends-on`-Abhängigkeit (`PASMetricDataView`)
und das SQL. Der Parameter-Slot ist hier leer, aber dort könnte beispielsweise ein Filter für einen
Berichtszeitraum eingefügt werden:

<div class="narrow" style="display: flex; justify-content: center">

<img src="submission-volume-query.avif" alt="SubmissionVolume as a SQLQuery in the Aidbox builder: a canonical URL, a depends-on dependency on PASMetricDataView, an empty parameters slot, and the aggregate SQL." width="520" />

</div>

Führt man sie aus, ergibt sich für unsere beiden Ansprüche, beide aus dem Jahr 2026: zwei eindeutige Exchanges, c1 und c2, also 2
Einreichungen, und drei Positions-Zeilen, also 3 Servicepositionen:

<div class="narrow">

| reporting_year | submission_count | service_item_count |
|----------------|------------------|--------------------|
| 2026           | 2                | 3                  |

</div>

## Lineage ohne Mehraufwand

In den meisten Stacks ist Lineage Zusatzarbeit: ein separates Tool oder ein Diagramm, das jemand
manuell aktuell hält. Aidbox leitet sie ab. Da jede SQLView und SQLQuery ihre Eingaben
über `relatedArtifact: depends-on` benennt, kennt Aidbox in dem Moment, in dem die Artefakte geladen werden,
den Abhängigkeitsgraph und visualisiert ihn – vom rohen Ressourcentyp bis zur Metrik.

Jeder Knoten lässt sich einzeln ausführen, sodass das Debugging konkret ist: Eine einzelne ViewDefinition, SQLView oder SQLQuery
wird für sich ausgeführt, ihr Ergebnis betrachtet, und eine Zahl in einem Diagramm lässt sich bis zum FHIRPath-
Ausdruck zurückverfolgen, der sie erzeugt hat.

Hier ist die Lineage, die Aidbox für die Einreichungsvolumen-Metrik zeichnet. `Claim`,
`Practitioner` und `ClaimResponse` werden in ViewDefinitions abgeflacht, die die
`ClaimWithProviderView`- und `ResponseResultView`-SQLViews speisen, dann das `PASMetricDataView`-
Modell, dann die `SubmissionVolume`-Abfrage:

![Aidbox lineage graph for the submission volume metric: Claim, Practitioner, and ClaimResponse flatten into ViewDefinitions, which feed the ClaimWithProviderView and ResponseResultView SQLViews, then the PASMetricDataView model, then the SubmissionVolume query.](lineage-graph.avif)

Der reale PAS-Graph ist größer: Dasselbe Modell (`PASMetricDataView`) speist die anderen
neun Metriken, von denen jede ihre Eingaben auf dieselbe Weise deklariert.

## Überall ausführbar, für jedes BI-Tool nutzbar

`$sqlquery-run` führt eine Metrik sofort gegen Live-Daten aus, was praktisch ist, während man
eine Metrik entwickelt oder eine Ad-hoc-Frage beantwortet.

Für Dashboards wird jede Metrik zu einer materialisierten Postgres-Sicht, vorberechnet und
in-place aktualisiert. Metabase, Tableau oder
Power BI verbinden sich mit einer einfachen Tabelle und sehen das darunterliegende FHIR nie. Es wird nichts exportiert,
und es gibt kein Warehouse zu synchronisieren; die Analytics liegen in derselben Postgres-Instanz wie die FHIR-
Daten.

## Was am Ende vorliegt

Die Metriken liegen am Ende als eine Handvoll gewöhnlicher FHIR-Ressourcen vor – **ViewDefinitions**,
**SQLViews** und **SQLQueries** –, keine benutzerdefinierte Pipeline. Das passt gut zu PAS, das sich noch im Wandel befindet:
PASMetricData ist eher eine Referenzform als eine feste, und die Metriken drum herum ändern sich weiter. Wenn das passiert,
bearbeitet man ein Artefakt, und der Rest des Graphs folgt. All das ist auch nicht PAS-spezifisch:
Jedes IG, das Metriken oder auch nur ein Logikmodell definiert, kann auf dieselbe Weise aufgebaut werden.

Da es sich um Ressourcen handelt, werden sie versioniert, in ein Paket gebündelt und mit einem einzigen
Upload installiert. In der Lineage-Ansicht kann jeder Knoten ad hoc ausgeführt, debuggt oder geändert werden, und
`$sqlquery-run` führt jeden beliebigen Ausschnitt aus, auf den man es zeigt: eine einzelne Sicht, den Pfad einer Metrik
zurück zur Quelle oder das gesamte Modell auf einmal.

> Möchten Sie PAS-Metriken auf Ihren eigenen Daten ausführen? Probieren Sie eine Sicht im
> [ViewDefinition builder](https://sqlonfhir.aidbox.app/) aus, oder bauen Sie die vollständige Pipeline
> selbst in [Aidbox](https://www.health-samurai.io/aidbox).
>
> Kostenträger, die mit der CMS-0057-F-Berichtspflicht zur Prior Authorization konfrontiert sind, erhalten Da Vinci PAS-Unterstützung,
> fertig paketiert und einsatzbereit, mit [Payerbox](https://www.health-samurai.io/cms-0057-f),
> der CMS-0057-F-Lösung von Health Samurai.
>
> [Sprechen Sie mit unserem Team](https://www.health-samurai.io/company#contact-form), um loszulegen.

### Siehe auch:
- [SQL on FHIR: Interoperable Analytics](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics) – das allgemeine Muster hinter dieser Pipeline

## Referenzen

- [Da Vinci PAS IG](https://hl7.org/fhir/us/davinci-pas/) und dessen
  [Metriken-Seite](https://build.fhir.org/ig/HL7/davinci-pas/metrics.html)
- [PASMetricData-Logikmodell](https://build.fhir.org/ig/HL7/davinci-pas/StructureDefinition-PASMetricData.html)
- [SQL on FHIR-Spezifikation](https://sql-on-fhir.org/ig/) und die
  [ViewDefinition-Ressource](https://sql-on-fhir.org/ig/StructureDefinition-ViewDefinition.html)
- [„SQL on FHIR: Interoperable Analytics", Nikolai Ryzhikov](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics)
- [„SQL on FHIR: tabular views of FHIR data using FHIRPath", npj Digital Medicine](https://www.nature.com/articles/s41746-025-01708-w)
- [FHIRPath](https://hl7.org/fhirpath/)
- [ViewDefinition builder](https://sqlonfhir.aidbox.app/)