SQL on FHIR
2.1.0-pre - release
SQL on FHIR, published by SQL on FHIR Working Group. This guide is not an authorized publication; it is the continuous build for version 2.1.0-pre built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/sql-on-fhir/ and changes regularly. See the Directory of published versions
| Official URL: http://sql-on-fhir.org/OperationDefinition/$sqlquery-run | Version: 2.1.0-pre | |||
| Active as of 2026-06-13 | Computable Name: SQLQueryRun | |||
Execute a SQLQuery Library against ViewDefinition tables.
Execute a SQLQuery Library against ViewDefinition tables synchronously.
Use Cases:
Endpoints:
| Level | Endpoint | Query Source |
|---|---|---|
| System | POST [base]/$sqlquery-run |
queryReference or queryResource |
| Type | POST [base]/Library/$sqlquery-run |
queryReference or queryResource |
| Instance | POST [base]/Library/[id]/$sqlquery-run |
The Library instance |
Execution Flow:
relatedArtifactparameters values to SQL placeholders_format=fhir)Implementations MUST ensure parameter values are safely bound to queries and not subject to SQL injection. Use parameterized queries or equivalent safe binding mechanisms where available. Simple string interpolation MUST NOT be used to implement parameter binding.
URL: [base]/$sqlquery-run
URL: [base]/Library/$sqlquery-run
URL: [base]/Library/[id]/$sqlquery-run
| Use | Name | Scope | Cardinality | Type | Binding | Documentation |
| IN | _format | system, type, instance | 0..1 | code | Output Format Codes (Extensible) | Output format for the result (json, ndjson, csv, parquet, fhir). Use fhir to return results as a FHIR Parameters resource. Optional; if omitted, the server returns ndjson by default. See Common Operation Behavior (operations-common.html). |
| IN | header | system, type, instance | 0..1 | boolean | Include CSV headers (default true). Applies only when csv output is requested. | |
| IN | queryReference | system, type | 0..1 | Reference | Reference to a SQLQuery Library stored on the server. | |
| IN | queryResource | system, type | 0..1 | Library | Inline SQLQuery Library resource to execute. | |
| IN | parameters | system, type, instance | 0..1 | Parameters | Input parameters for the query. Parameters are bound by name to parameters declared in the SQLQuery Library (Library.parameter.name). Parameter types are mapped using the appropriate value[x] type matching the declared parameter type. | |
| IN | source | system, type, instance | 0..1 | string | External data source containing the ViewDefinition tables. | |
| IN | _limit | system, type, instance | 0..1 | integer | Maximum number of rows to return. | |
| OUT | return | 1..1 | Binary | Query results in the requested output format, returned as a raw binary stream in the format's native media type, not a serialized Binary resource envelope. When _format=fhir is requested, the response is a Parameters resource instead. See Common Operation Behavior (operations-common.html). |
The operation is invoked with POST. The following input parameters are passed
inside a Parameters resource in the request body.
| Name | Type | Scope | Required | Max | Description |
|---|---|---|---|---|---|
| _format | code | system, type, instance | No | 1 | Output format: json, ndjson, csv, parquet, fhir. Details |
| header | boolean | system, type, instance | No | 1 | Include CSV headers (default: true). Only applies to csv format |
| queryReference | Reference | system, type | Conditional¹ | 1 | Reference to a SQLQuery Library stored on the server |
| queryResource | Resource | system, type | Conditional¹ | 1 | Inline SQLQuery Library resource to execute |
| parameters | Parameters | system, type, instance | No | 1 | Input parameters bound by name to parameters declared in the SQLQuery Library |
| source | string | system, type, instance | No | 1 | External data source containing the ViewDefinition tables (e.g. URI, bucket name) |
| _limit | integer | system, type, instance | No | 1 | Maximum number of rows to return |
¹ Either queryReference or queryResource is required at the system and type
levels; neither is allowed at the instance level (the Library is identified by
the path).
| Name | Type | Description |
|---|---|---|
| return | Binary | Query results as a raw stream in the format’s native media type, not a serialized Binary envelope (a Parameters resource when _format=fhir is requested). See Return Representation |
When supplied, _limit is the maximum number of rows the server returns to the
client.
Servers MAY enforce a maximum value, silently capping client-supplied limits at
a smaller server-defined maximum. The cap is applied to the final result set
after the SQL query (including any in-query LIMIT) has been evaluated;
implementations are free to push the limit down into the query as an
optimisation, but the observable behaviour is post-evaluation.
Returning fewer rows than the client requested - whether because the query yielded fewer rows or because the server applied its own cap - is not treated as an error.
The supported formats (json, ndjson, csv, parquet, fhir), the default,
the Accept-vs-_format precedence rule, the raw-vs-envelope representation
axis, and transfer framing are defined in
Common Operation Behavior and apply identically to
this operation:
json, ndjson and csv by default; servers MAY
support parquet and fhir, and SHALL document supported formats in the
CapabilityStatement._format is omitted (and no format is derivable from Accept), the server
SHALL return the result in ndjson format._format is supplied, its value SHALL take precedence over Accept.Transfer-Encoding: chunked; chunked
transfer is independent of the format. See
Streaming and Transfer Encoding.When the SQLQuery Library is stored on the server, invoke directly on the instance:
POST /Library/patient-bp-query/$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "_format", "valueCode": "csv" },
{ "name": "parameters", "resource": {
"resourceType": "Parameters",
"parameter": [
{ "name": "patient_id", "valueString": "Patient/123" },
{ "name": "from_date", "valueDate": "2024-01-01" }
]
}}
]
}
Reference a stored Library by URL or relative reference:
POST /Library/$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "_format", "valueCode": "json" },
{ "name": "queryReference", "valueReference": {
"reference": "Library/patient-bp-query"
}},
{ "name": "parameters", "resource": {
"resourceType": "Parameters",
"parameter": [
{ "name": "patient_id", "valueString": "Patient/123" }
]
}}
]
}
Pass the SQLQuery Library inline for ad-hoc queries:
POST /Library/$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "_format", "valueCode": "ndjson" },
{ "name": "queryResource", "resource": {
"resourceType": "Library",
"meta": { "profile": ["https://sql-on-fhir.org/ig/StructureDefinition/SQLQuery"] },
"type": { "coding": [{ "system": "https://sql-on-fhir.org/ig/CodeSystem/LibraryTypesCodes", "code": "sql-query" }] },
"status": "active",
"relatedArtifact": [
{ "type": "depends-on", "resource": "https://example.org/ViewDefinition/patient_view", "label": "p" }
],
"content": [{
"contentType": "application/sql",
"data": "U0VMRUNUIHAuaWQsIHAubmFtZSBGUk9NIHAgV0hFUkUgcC5hY3RpdmUgPSB0cnVl",
"extension": [{
"url": "https://sql-on-fhir.org/ig/StructureDefinition/sql-text",
"valueString": "SELECT p.id, p.name FROM p WHERE p.active = true"
}]
}]
}}
]
}
Invoke at the server base without a resource type. This is useful when the server supports SQLQuery Libraries but does not expose them as FHIR Library resources:
POST /$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "_format", "valueCode": "csv" },
{ "name": "queryReference", "valueReference": {
"reference": "Library/patient-bp-query"
}},
{ "name": "parameter", "part": [
{ "name": "name", "valueString": "patient_id" },
{ "name": "value", "valueString": "Patient/123" }
]}
]
}
_format omitted)When _format is omitted, the server returns the result in ndjson format:
POST /Library/patient-bp-query/$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "parameters", "resource": {
"resourceType": "Parameters",
"parameter": [
{ "name": "patient_id", "valueString": "Patient/123" }
]
}}
]
}
HTTP/1.1 200 OK
Content-Type: application/x-ndjson
{"patient_id":"Patient/123","systolic":120,"effective_date":"2024-01-15"}
{"patient_id":"Patient/123","systolic":118,"effective_date":"2024-02-20"}
_limitUse _limit to ask the server to return at most a given number of rows. The
server may return fewer rows if the query yields fewer or if its configured
maximum is smaller; see Row Limit for the full semantics.
POST /Library/patient-bp-query/$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "_format", "valueCode": "csv" },
{ "name": "_limit", "valueInteger": 100 }
]
}
For flat formats (csv, json, ndjson, parquet), the response body is the
raw payload in the format’s native media type (the Binary stream), not a
serialized Binary resource envelope; Content-Type is set to that media type.
The response MAY be sent with Transfer-Encoding: chunked regardless of format.
See Return Representation and
Streaming.
HTTP/1.1 200 OK
Content-Type: text/csv
patient_id,systolic,effective_date
Patient/123,120,2024-01-15
Patient/123,118,2024-02-20
When _format=fhir, the response is a FHIR Parameters resource with each row as a
repeating row parameter.
POST /Library/patient-bp-query/$sqlquery-run HTTP/1.1
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{ "name": "_format", "valueCode": "fhir" },
{ "name": "parameters", "resource": {
"resourceType": "Parameters",
"parameter": [
{ "name": "patient_id", "valueString": "Patient/123" }
]
}}
]
}
Response:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "row",
"part": [
{ "name": "patient_id", "valueString": "Patient/123" },
{ "name": "systolic", "valueInteger": 120 },
{ "name": "effective_date", "valueDate": "2024-01-15" }
]
},
{
"name": "row",
"part": [
{ "name": "patient_id", "valueString": "Patient/123" },
{ "name": "systolic", "valueInteger": 118 },
{ "name": "effective_date", "valueDate": "2024-02-20" }
]
}
]
}
When a query returns zero rows, the response is a Parameters resource with no
parameter elements:
{
"resourceType": "Parameters"
}
When _format=fhir, each result column must be encoded using a FHIR value[x]
type. The following table defines the mapping from
ISO/IEC 9075 SQL types to FHIR
parameter value types.
| ISO/IEC 9075 SQL type | FHIR value type |
|---|---|
| BOOLEAN | valueBoolean |
| TINYINT, SMALLINT, INT, INTEGER | valueInteger |
| BIGINT | valueInteger64 |
| DECIMAL, NUMERIC | valueDecimal |
| REAL | valueDecimal |
| FLOAT, DOUBLE PRECISION | valueDecimal |
| CHARACTER, CHARACTER VARYING, CHARACTER LARGE OBJECT | valueString |
| BINARY, BINARY VARYING, BINARY LARGE OBJECT | valueBase64Binary |
| DATE | valueDate |
| TIME, TIME WITH TIME ZONE | valueTime |
| TIMESTAMP | valueDateTime |
| TIMESTAMP WITH TIME ZONE | valueInstant |
SQL NULL values are represented by omitting the corresponding part from the row parameter.
Conversion of REAL, FLOAT, and DOUBLE PRECISION values to valueDecimal may
introduce representation artefacts due to the difference between binary and
decimal floating point.
TIMESTAMP WITH TIME ZONE values may carry sub-millisecond precision (e.g.
microseconds), but FHIR instant supports at most millisecond precision.
Implementations SHOULD round to the nearest millisecond when converting to
valueInstant.
TIMESTAMP (without time zone) values are converted to valueDateTime without a
timezone offset. FHIR dateTime permits values with or without a timezone, so
the absence of timezone information is preserved rather than trying to infer a
time zone.
ISO/IEC 9075 types not listed in this table (such as INTERVAL, ARRAY, XML, ROW,
and MULTISET) are not supported. If a query produces a result column with an
unsupported type, the server MUST return a 422 Unprocessable Entity error.
Query authors can work around this by casting unsupported types to a supported
type within the SQL query.
Query parameters are passed as a nested Parameters resource, following the
same pattern as the
CQL $evaluate operation.
See Parameter Types on the
SQLQuery profile for the binding rules and the mapping from
Library.parameter.type to the value[x] element to use.
| Status | Condition |
|---|---|
400 Bad Request |
Missing required parameter, unknown parameter name, or value type mismatch |
404 Not Found |
Library or ViewDefinition not found |
422 Unprocessable Entity |
SQL execution error, or unsupported SQL column type when using _format=fhir (see type mapping) |