Team Ai
Datasetpublic

adelelsayed1991/fhirsql-reasoning-sql

FHIR-to-SQL with Database-Resolved Clinical Terminology Natural-language hospital questions paired with a structured JSON query plan and compiled DuckDB SQL, over a FHIR-derived clinical schema. Built entirely from synthetic Synthea patients — no real patient data. Companion to the paper Plan-Then-Compile: Turning a General-Purpose Coder Model into a FHIR Data Analyst. Code & paper: https://github.com/adelelsayed/fhirsql-reasoning-sql Adapters:… See the full description on the dataset page: https://huggingface.co/datasets/adelelsayed1991/fhirsql-reasoning-sql.

sourceHugging Facecc-by-4.0updated 1mo agoView on Hugging Face
0likes107downloads
schema.sql232 linesDownload Raw Back to root
1-- FHIR-SQL fine-tuning study: frozen core clinical schema.
2--
3-- This is the benchmark-facing schema shown to models in every prompt (benchmark
4-- authoring, SFT prompt format, RL reward execution). It is a deliberately curated
5-- subset of the full flattened data -- see METHODOLOGY_LOG.md for the two-layer
6-- rationale (full fidelity in the database, curated scope in what models see) and
7-- the token-cost/scope reasoning.
8--
9-- Generated from the actual column types DuckDB inferred when loading
10-- data/train.duckdb, not hand-assumed -- see scripts/flatten_to_duckdb.py for
11-- the extraction logic that produces this shape.
12--
13-- Version stamp:
14--   Date frozen:        2026-08-02
15--   Synthea build:      v3.4.0-18-ga07a65555 (git-describe string embedded in
16--                        generated Patient resources; downloaded from the
17--                        GitHub v4.0.0 release page -- see methodology log)
18--   Train population:   18,999 patients (target was ~15,000; see log for
19--                        per-batch seed/state/age-bracket design)
20--   Held-out population: 6,383 patients (target was ~5,000)
21--   Populations verified disjoint: 0 patient_id overlap between train and held-out
22--
23-- Every number produced downstream (benchmark accuracy, cost tables, etc.) is
24-- relative to this artifact. Do not modify this file without a note on what
25-- changed and why.
26--
27-- Provider attribution: Synthea generates exactly one participant per encounter,
28-- typed "primary performer" only -- it does not distinguish admitting/attending/
29-- consulting roles, so those remain unanswerable regardless of schema design.
30-- Procedure.performer is never populated by this Synthea version (0/29,947 in a
31-- full batch) -- procedure-level provider attribution is not available at all.
32--
33-- Naming convention: columns are named to match FHIR element names directly,
34-- so a model's clinical-language understanding maps onto the schema with as
35-- little translation as possible:
36--   - Primary key: `id` (matches every FHIR resource's own `id` element).
37--   - Foreign keys: `patient_id`, `encounter_id` (SQL join-key convention;
38--     not itself a literal FHIR field name, since FHIR expresses this via
39--     subject/patient/encounter *reference* elements, but resolving those
40--     references to a flat join key needs a name, and `<type>_id` is the
41--     clearest SQL-side compromise).
42--   - Primary coding triple on each table: `code`, `system`, `display`
43--     (matches FHIR Coding.code/.system/.display exactly).
44--   - Where a resource's own field name differs from the generic "code"
45--     (Encounter.type, Encounter.class, Immunization.vaccineCode,
46--     CarePlan.category), the coding triple is prefixed with that field name
47--     instead: `type_code/type_system/type_display`, `class_code`,
48--     `vaccineCode/vaccineCode_system/vaccineCode_display`,
49--     `category_code/category_system/category_display`.
50--   - Status/descriptive fields: exact camelCase FHIR element names
51--     (clinicalStatus, verificationStatus, intent, criticality).
52--   - Dates: exact FHIR element names (birthDate, deceasedDateTime,
53--     onsetDateTime, abatementDateTime, recordedDate, effectiveDateTime,
54--     authoredOn, performedDateTime, occurrenceDateTime); Period-typed
55--     start/end kept as `period_start`/`period_end` (Period.start/.end).
56--   - value[x]: `valueQuantity`, `unit` (Quantity.unit), `valueCodeableConcept`
57--     (+ `valueCodeableConcept_system`), `valueString`.
58--   - Provider-reference columns match the FHIR field they were extracted
59--     from: `requester_npi`/`requester_name` on medication_request (from
60--     MedicationRequest.requester), `participant_npi`/`participant_name` on
61--     encounter (from Encounter.participant).
62--   - `race`/`ethnicity` on patient (US-Core extensions -- see
63--     scripts/flatten_to_duckdb.py's us_core_ext_text macro).
64--   - `imaging_study` (ImagingStudy resource) makes radiology-volume questions
65--     answerable (department-level radiology questions remain unanswerable --
66--     no department/service-line concept exists anywhere in Synthea's FHIR
67--     output).
68--
69-- Indexes: secondary (ART) indexes are added directly to train.duckdb and
70-- heldout.duckdb (not a change to this file -- no column/table/logical change,
71-- only a physical one) on the coding-triple columns (condition.code,
72-- observation.code, medication_request.code, encounter.class_code,
73-- encounter.type_code, procedure.code, immunization.vaccineCode, allergy.code,
74-- careplan.category_code, diagnostic_report.code, imaging_study.procedureCode,
75-- imaging_study.modality), to support the RL execution-efficiency reward term.
76-- patient_id/encounter_id deliberately NOT indexed -- DuckDB's ART index isn't
77-- used by the optimizer to accelerate joins, only point/highly-selective
78-- (<0.1% of rows) filters. See METHODOLOGY_LOG.md for the full verification
79-- history of this schema and its indexes.
80
81CREATE TABLE patient (
82    id                    VARCHAR PRIMARY KEY,
83    gender                VARCHAR,
84    birthDate             DATE,
85    deceasedDateTime      TIMESTAMP,
86    maritalStatus         VARCHAR,
87    state                 VARCHAR,     -- address[0].state
88    city                  VARCHAR,     -- address[0].city
89    postalCode            VARCHAR,     -- address[0].postalCode
90    race                  VARCHAR,     -- US-Core race extension, ombCategory text
91    ethnicity             VARCHAR      -- US-Core ethnicity extension, ombCategory text
92);
93
94CREATE TABLE condition (
95    id                    VARCHAR PRIMARY KEY,
96    patient_id            VARCHAR,     -- join key -> patient.id
97    encounter_id          VARCHAR,     -- join key -> encounter.id
98    code                  VARCHAR,
99    system                VARCHAR,     -- kept alongside code deliberately: code-system confusion (SNOMED vs ICD-10 vs LOINC) is a failure mode to observe
100    display               VARCHAR,
101    clinicalStatus        VARCHAR,
102    verificationStatus    VARCHAR,
103    onsetDateTime         TIMESTAMP,
104    abatementDateTime     TIMESTAMP,
105    recordedDate          TIMESTAMP
106);
107
108CREATE TABLE observation (
109    id                    VARCHAR PRIMARY KEY,
110    patient_id            VARCHAR,     -- join key -> patient.id
111    encounter_id          VARCHAR,     -- join key -> encounter.id
112    code                  VARCHAR,
113    system                VARCHAR,
114    display               VARCHAR,
115    category              VARCHAR,
116    status                VARCHAR,
117    effectiveDateTime     TIMESTAMP,
118    valueQuantity         DOUBLE,      -- value[x] flattened per plan design rule
119    unit                  VARCHAR,
120    valueCodeableConcept  VARCHAR,
121    valueCodeableConcept_system VARCHAR,  -- code-system pairing for the value itself, when value[x] is coded
122    valueString           VARCHAR
123);
124
125CREATE TABLE medication_request (
126    id                    VARCHAR PRIMARY KEY,
127    patient_id            VARCHAR,     -- join key -> patient.id
128    encounter_id          VARCHAR,     -- join key -> encounter.id
129    code                  VARCHAR,
130    system                VARCHAR,
131    display               VARCHAR,
132    status                VARCHAR,
133    intent                VARCHAR,
134    authoredOn            TIMESTAMP,
135    requester_npi         VARCHAR,     -- prescribing physician's NPI (from MedicationRequest.requester)
136    requester_name        VARCHAR
137);
138
139CREATE TABLE encounter (
140    id                    VARCHAR PRIMARY KEY,
141    patient_id            VARCHAR,     -- join key -> patient.id
142    class_code            VARCHAR,     -- Encounter.class.code (AMB/EMER/IMP/HH/VR)
143    type_code             VARCHAR,     -- Encounter.type[0].coding[0]
144    type_system           VARCHAR,
145    type_display          VARCHAR,
146    status                VARCHAR,
147    period_start          TIMESTAMP,
148    period_end            TIMESTAMP,
149    reasonCode            VARCHAR,
150    participant_npi       VARCHAR,     -- primary-performer physician's NPI (Synthea models only one role per encounter, not admitting/attending/etc separately)
151    participant_name      VARCHAR
152);
153
154CREATE TABLE procedure (
155    id                    VARCHAR PRIMARY KEY,
156    patient_id            VARCHAR,     -- join key -> patient.id
157    encounter_id          VARCHAR,     -- join key -> encounter.id
158    code                  VARCHAR,
159    system                VARCHAR,
160    display               VARCHAR,
161    status                VARCHAR,
162    performedDateTime     TIMESTAMP
163    -- Note: Procedure.performer (physician who performed it) is never populated
164    -- by this Synthea version (confirmed 0/29,947) -- not available at all.
165);
166
167CREATE TABLE immunization (
168    id                    VARCHAR PRIMARY KEY,
169    patient_id            VARCHAR,     -- join key -> patient.id
170    encounter_id          VARCHAR,     -- join key -> encounter.id
171    vaccineCode           VARCHAR,
172    vaccineCode_system    VARCHAR,
173    vaccineCode_display   VARCHAR,
174    status                VARCHAR,
175    occurrenceDateTime    TIMESTAMP
176);
177
178CREATE TABLE allergy (
179    id                    VARCHAR PRIMARY KEY,
180    patient_id            VARCHAR,     -- join key -> patient.id
181    code                  VARCHAR,
182    system                VARCHAR,
183    display               VARCHAR,
184    clinicalStatus        VARCHAR,
185    verificationStatus    VARCHAR,
186    category              VARCHAR,
187    criticality           VARCHAR,
188    recordedDate          TIMESTAMP
189);
190
191CREATE TABLE careplan (
192    id                    VARCHAR PRIMARY KEY,
193    patient_id            VARCHAR,     -- join key -> patient.id
194    encounter_id          VARCHAR,     -- join key -> encounter.id
195    category_code         VARCHAR,     -- CarePlan.category[0].coding[0]
196    category_system       VARCHAR,
197    category_display      VARCHAR,
198    status                VARCHAR,
199    period_start          TIMESTAMP,
200    period_end            TIMESTAMP
201);
202
203CREATE TABLE diagnostic_report (
204    id                    VARCHAR PRIMARY KEY,
205    patient_id            VARCHAR,     -- join key -> patient.id
206    encounter_id          VARCHAR,     -- join key -> encounter.id
207    code                  VARCHAR,
208    system                VARCHAR,
209    display               VARCHAR,
210    category              VARCHAR,
211    status                VARCHAR,
212    effectiveDateTime     TIMESTAMP
213);
214
215CREATE TABLE imaging_study (
216    id                    VARCHAR PRIMARY KEY,
217    patient_id            VARCHAR,     -- join key -> patient.id
218    encounter_id          VARCHAR,     -- join key -> encounter.id
219    status                VARCHAR,
220    started               TIMESTAMP,
221    numberOfSeries        INTEGER,
222    numberOfInstances     INTEGER,
223    procedureCode         VARCHAR,     -- the imaging procedure performed, e.g. "Plain X-ray of ankle region"
224    procedureCode_system  VARCHAR,
225    procedureCode_display VARCHAR,
226    modality               VARCHAR,    -- DICOM modality code, e.g. "DX" = Digital Radiography (from series[0])
227    modality_system        VARCHAR,
228    modality_display       VARCHAR,
229    bodySite               VARCHAR,    -- from series[0]
230    bodySite_display       VARCHAR
231);
232