SQL on FHIR WG Meetings



SQL on FHIR WG Meeting — July 8, 2025
Nikolai Ryzhikov
CTO at Health Samurai
Steve Munini
CEO and CTO, Helios Software
Arjun Sanyal
Principal Antidote Solutions
Gino Canessa
Principal Software Engineer at Microsoft
AD
Adam Culbertson
Jul 8, 2025
Topics discussed:
- Nikolai asked whether format and filters should be set per view or once for the whole export. Steve Munini wanted them on the export — people work in one format per project, and wanting two formats in one request would be odd. Gino Canessa agreed and put it plainly: he wouldn't want to build a pipeline that produced a Parquet export and a CSV export from the same call, so issue two requests. The nested per-view parameters came out for the same reason Steve gave — nesting leaves implementers asking when to use the nested slot versus the root, and what happens if you fill in both. It also can't survive a GET, since those only carry simple types.
- Arjun Sanyal questioned why $export takes multiple views at all, given nothing joins them — convenience only? Nikolai's answer was consistency: one call lets the server snapshot and export every view against the same data, and two separate requests guarantee you nothing.
- Multiple views then created a problem Gino spotted: if you can pass the same view twice with different filters or groups, the outputs need a key, and the view's name isn't unique. So each view gets an id, defaulting to the view name, and it's only required once you have more than one — the single-view case stays simple.
- Steve had started implementing _page and hit a wall: FHIR search has a Bundle with a tidy slot for links, but a CSV or a Parquet file has nowhere to put them. He found the RFC that standardises pagination links in headers; Gino noted Bundle.link already uses that same RFC and only lives in the body because messaging has no headers. Paging was dropped for now, with headers as the route back in if anyone asks.
- The long one was _count. Gino explained the FHIR distinction: _count is page size, while _max-results — added in R5 — is a hard truncation, so the server can throw its cursor away and stop tracking your search. Steve preferred truncation, since $run is really a preview. That exposed the deeper question: one resource can produce many rows, so does the number count resources going in or rows coming out? Nikolai wanted to match FHIR and count resources; Gino's line was "we're in SQL land, we do it by rows". They landed on _limit, which sidesteps the collision entirely, with the underscore because the FHIR style guide reserves it for parameters that aren't tied to a resource.
- Nikolai suggested underscoring every parameter so anything without one could be read as a search parameter. Gino argued against: you'd risk collisions, and plenty of search parameters already carry underscores — _id, _lastUpdated, _profile, _list, _content. John Grimes' question about default type hints came up in his absence and was held for him, though the shape of the problem surfaced: FHIR dateTime is a strange beast because partial dates make it a range rather than a point, so it won't map to an ISO type, whereas instant looks safely convertible to a timestamp.