---
{
  "title": "Métricas Da Vinci PAS con SQL on FHIR en Aidbox",
  "description": "Cálculo de las métricas operativas Da Vinci PAS con SQL on FHIR en Aidbox.",
  "date": "2026-06-16",
  "author": "Akim Khalitov",
  "reading-time": "5 minutes",
  "tags": [
    "Analytics",
    "SQL on FHIR",
    "Prior Authorization"
  ],
  "tldr": "El artículo muestra cómo calcular las métricas operativas Da Vinci PAS relevantes para CMS-0057 directamente sobre datos FHIR de autorización previa usando SQL on FHIR, sin necesidad de construir un almacén de datos independiente. Se presentan las herramientas de SQL on FHIR, las ViewDefinitions, los SQLViews y los SQLQueries, y lo poco que se necesita para construir estos artefactos, empaquetarlos y posteriormente materializarlos para alimentar herramientas de BI como Metabase, Tableau o Power BI."
}
---

> For the complete documentation index, see [llms.txt](https://www.health-samurai.io/llms.txt).
> Use it to discover all available pages before guessing URLs.

---
La autorización previa es un punto de fricción persistente en el sistema sanitario de EE. UU., y la
presión para medirla no deja de crecer: los pagadores quieren saber dónde se estanca, y
reportarla está en camino de convertirse en un requisito regulatorio. Eso implica medir el
volumen de envíos, la tasa de errores y el tiempo hasta la decisión.

El [IG Da Vinci PAS](https://hl7.org/fhir/us/davinci-pas/) define
[diez métricas operativas](https://build.fhir.org/ig/HL7/davinci-pas/metrics.html)
e incluye un modelo lógico
[`PASMetricData`](https://build.fhir.org/ig/HL7/davinci-pas/StructureDefinition-PASMetricData.html)
que sugiere los datos en los que se basan dichas métricas.

Calcularlas habitualmente implica copiar los datos a un sistema analítico independiente y
reconstruir cada métrica allí, un trabajo a medida que se repite en cada implantación y se
desincroniza con el origen. Queríamos lo contrario: definir cada métrica una sola vez, ejecutarla
junto a los datos y leerla con las herramientas de BI que ya se utilizan. Como la transformación es
declarativa y permanece en la base de datos, no hay nada que copiar para mantener sincronizado ni
una segunda pila analítica que construir. Aidbox ya disponía de una forma de hacer esto:
SQL on FHIR integrado.

## SQL on FHIR en un minuto

[SQL on FHIR](https://sql-on-fhir.org/ig/) estandariza tanto el aplanamiento como las
consultas sobre él, en lugar de que cada proveedor invente su propia forma de consultar recursos
anidados. Sus métricas se convierten en artefactos FHIR portátiles y estándar, analítica
interoperable,
[explicada en detalle aquí](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics).
Las piezas:

1. **[ViewDefinition](https://sql-on-fhir.org/ig/StructureDefinition-ViewDefinition.html)**:
   un formato portátil para definir vistas tabulares de datos FHIR.
2. **[SQLQuery](https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/StructureDefinition-SQLQuery.html)**
   y **SQLView**: SQL compartible sobre dichas vistas, basado en el recurso FHIR
   [Library](https://hl7.org/fhir/R5/library.html). Un SQLQuery admite
   parámetros, por ejemplo un rango de fechas de reporte; un SQLView no tiene parámetros.
3. **[HTTP API](https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/index.html#http-api)**:
   operaciones FHIR estándar (`$viewdefinition-run`, `$sqlquery-run`) para ejecutar vistas
   y consultas.

Aidbox ejecuta todo esto contra el mismo Postgres que respalda la API FHIR en producción, de modo
que los datos y la analítica conviven en una sola base de datos.

## Cinco capas, del FHIR en bruto al dashboard

Los datos PAS son complicados de aplanar. Derivan de X12, con respuestas que llegan a lo largo de
varios ciclos, y métricas que abarcan Claim, ClaimResponse y el proveedor y la cobertura
asociados. Ninguna vista
individual proporciona una fila de métrica, por lo que el pipeline se construye en capas, cada una
leyendo de la anterior, y el grafo de esas capas constituye el linaje.

Apilar vistas planas en un modelo compartido y luego añadir las métricas encima es el patrón
general de analítica descrito en detalle en
[SQL on FHIR: Interoperable Analytics](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics);
aquí lo aplicamos a PAS:

<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>

El IG define diez métricas:

<div class="narrow">

| Métrica | Qué mide |
|---------|----------|
| 1. volumen de envíos | Volumen de envíos PAS (como 278 y elementos de línea) |
| 2. actualizaciones, cancelaciones y consultas | Volumen de actualizaciones, cancelaciones y consultas PAS |
| 3. consultas de proveedores no solicitantes | Volumen de consultas realizadas por otros distintos al proveedor solicitante |
| 4. porcentaje de errores | % de envíos PAS que devuelven un error (por tipo y pagador) |
| 5. porcentaje de resolución final en envío inicial | % de envíos PAS que devuelven un resultado final en el envío inicial (cualquier elemento y todos los elementos) |
| 6. volumen de pendientes y resolución | Volumen de elementos de línea con un PEND inicial y número de PENDS resueltos y (más complejo) tiempo medio de resolución de cada PEND |
| 7. tiempo hasta el resultado final | Tiempo total desde el envío inicial hasta el resultado final de PA para todos los elementos de línea |
| 8. segmentación | Todo lo anterior por pagador/proveedor (según la métrica) y a lo largo del tiempo |
| 9. solicitudes pendientes | Solicitudes PAS pendientes |
| 10. antigüedad de pendientes | Antigüedad de las solicitudes en estado PENDED |

</div>

Desarrollaremos la primera, el volumen de envíos, por ser la más sencilla. La
trazamos capa por capa, comenzando por la Capa 1, los recursos en bruto.

**Capa 1:** tomamos dos reclamaciones de preautorización, `c1` con dos elementos de línea y `c2` con
uno. Aquí está `c1` como JSON anidado:

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

**Capa 2:** una ViewDefinition realiza el aplanamiento. Un `where` conserva las reclamaciones de
preautorización y `forEach` sobre `item` convierte el array en una fila por elemento. Cada columna es
una expresión FHIRPath: `getResourceKey()` y `getReferenceKey()` para ids y referencias, rutas
ordinarias para el resto, incluso valores enterrados en extensiones PAS, sin ningún análisis
sintáctico personalizado:

```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" }] }
  ]
}
```

Para ambas reclamaciones, esto da una fila por elemento:

<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>

**Capa 3:** un SQLView, `ClaimWithProviderView`, une `ClaimView` con `PractitionerView`
para añadir el NPI del proveedor:

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

lo que da:

<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>

**Capa 4:** el modelo.

El lado de la respuesta, `ResponseResultView`, se construye como el lado de la reclamación:
una ViewDefinition aplana cada elemento de `ClaimResponse` y un SQLView expone su
`claim`, `item` y `result`. `PASMetricDataView` realiza un left-join de cada elemento de
reclamación con su respuesta, de modo que cada fila contiene tanto la solicitud como su resultado,
el modelo PASMetricData realizado aquí como una fila por elemento de línea:

```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
```

lo que da el modelo compartido sobre el que se ejecuta cada métrica:

<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>

**Capa 5:** el volumen de envíos es un agregado sobre ese modelo, un SQLQuery. Es
una métrica de adopción, por lo que cuenta envíos y elementos por año de reporte, que un
dashboard puede filtrar al año que necesite:

```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
```

Como recurso SQLQuery incluye una URL canónica, su `depends-on` (`PASMetricDataView`)
y el SQL. El apartado de parámetros está vacío aquí, pero es donde podría conectarse un filtro como
un rango de fechas de reporte:

<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>

Al ejecutarlo con nuestras dos reclamaciones, ambas de 2026: dos intercambios distintos, c1 y c2,
es decir, 2 envíos, y tres filas de elementos, es decir, 3 elementos de servicio:

<div class="narrow">

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

</div>

## Linaje sin esfuerzo adicional

En la mayoría de las pilas, el linaje es trabajo extra: una herramienta separada o un diagrama que
alguien actualiza manualmente. Aidbox lo deriva automáticamente. Como cada SQLView y SQLQuery nombra
sus entradas con `relatedArtifact: depends-on`, en el momento en que se cargan los artefactos Aidbox
conoce el grafo de dependencias y lo dibuja, desde el tipo de recurso en bruto hasta la métrica.

Cada nodo se ejecuta en su lugar, por lo que la depuración es concreta: ejecute una única
ViewDefinition, SQLView o SQLQuery por separado, vea lo que devuelve y rastree un número en un
gráfico hasta el FHIRPath que lo produjo.

Aquí está el linaje que Aidbox dibuja para la métrica de volumen de envíos. `Claim`,
`Practitioner` y `ClaimResponse` se aplanan en ViewDefinitions, que alimentan los
SQLViews `ClaimWithProviderView` y `ResponseResultView`, luego el modelo `PASMetricDataView`
y finalmente la consulta `SubmissionVolume`:

![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)

El grafo PAS real es mayor: el mismo modelo (`PASMetricDataView`) alimenta las otras
nueve métricas, cada una declarando sus entradas del mismo modo.

## Ejecútelo en cualquier lugar, sirva cualquier herramienta de BI

`$sqlquery-run` ejecuta una métrica al instante sobre datos en tiempo real, lo cual resulta práctico
mientras se está construyendo una métrica o respondiendo a una pregunta puntual.

Para dashboards, cada métrica se convierte en una vista materializada de Postgres, precalculada y
actualizada en su lugar. Metabase, Tableau o
Power BI se conectan a una tabla ordinaria y no ven el FHIR subyacente. No se exporta nada
y no hay ningún almacén que sincronizar; la analítica reside en el mismo Postgres que los datos FHIR.

## Con qué se queda al final

Las métricas acaban siendo un puñado de recursos FHIR ordinarios, **ViewDefinitions**,
**SQLViews** y **SQLQueries**, no un pipeline personalizado. Esto encaja bien con PAS, que todavía
está evolucionando: PASMetricData es una forma de referencia más que una forma fija, y las métricas
a su alrededor siguen cambiando. Cuando lo hacen, se edita un artefacto y el resto del grafo
se actualiza. Nada de esto es específico de PAS tampoco: cualquier IG que defina métricas, o
simplemente un modelo lógico, puede construirse del mismo modo.

Al ser recursos, se versionan, se agrupan en un paquete y se instalan con una sola carga. En la
vista de linaje se puede ejecutar, depurar o modificar cualquier nodo de forma puntual, y
`$sqlquery-run` ejecuta cualquier fragmento al que apunte: una única vista, el camino de una
métrica hasta el origen, o el modelo completo de una vez.

> ¿Desea ejecutar métricas PAS sobre sus propios datos? Pruebe una vista en el
> [constructor de ViewDefinition](https://sqlonfhir.aidbox.app/), o construya el pipeline completo
> usted mismo en [Aidbox](https://www.health-samurai.io/aidbox).
>
> Los pagadores que se enfrentan al reporte de autorización previa de CMS-0057-F pueden obtener el
> soporte Da Vinci PAS empaquetado y listo para ejecutarse con [Payerbox](https://www.health-samurai.io/cms-0057-f),
> la solución CMS-0057-F de Health Samurai.
>
> [Hable con nuestro equipo](https://www.health-samurai.io/company#contact-form) para comenzar.

### Véase también:
- [SQL on FHIR: Interoperable Analytics](https://www.health-samurai.io/articles/sql-on-fhir-interoperable-analytics), el patrón general detrás de este pipeline

## Referencias

- [IG Da Vinci PAS](https://hl7.org/fhir/us/davinci-pas/) y su
  [página de métricas](https://build.fhir.org/ig/HL7/davinci-pas/metrics.html)
- [Modelo lógico PASMetricData](https://build.fhir.org/ig/HL7/davinci-pas/StructureDefinition-PASMetricData.html)
- [Especificación SQL on FHIR](https://sql-on-fhir.org/ig/) y el
  [recurso ViewDefinition](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/)
- [Constructor de ViewDefinition](https://sqlonfhir.aidbox.app/)