Stiekema StudioNederlands

Case sheet

Survey-sync

A daily sync that puts survey data from an external platform into the data warehouse of a Dutch trade union, with an audit trail of every change per answer.

XBAS Business Intelligence · Almere NL · Case survey-sync

Diagram of the survey-sync: on the left the survey platform with three surveys, in the middle the high-watermark decision (skip without an API call, or fetch with a MERGE), on the right the table per survey with a dotted new column and the temporal history table behind it, at the bottom the log table with the four statuses per run.
Plate · Survey-sync · diagram in Dutch

Summary

Survey-sync checks per survey on an external survey platform whether new responses have come in, and writes them to the data warehouse. Every survey gets its own table with a dynamic schema: columns are not fixed in advance but discovered from the incoming data on each run, and new questions automatically lead to new columns. The sync is idempotent and incremental: a high watermark per survey decides whether an API call is needed at all, and a MERGE updates existing responses without ever deleting anything. This is the first of three steps in a larger reporting pipeline.

The brief

Survey responses had to land in the data warehouse automatically and repeatably, keeping the full change history per response, so that reporting can run on the latest state without older states being lost.

What I built

  • A Python script that checks per survey, through the REST API of the survey platform, whether there are new responses, paging through the full result
  • A dynamic table schema per survey: unknown surveys automatically get a table, new questions automatically get a column via ALTER TABLE
  • System-versioned temporal tables per survey, with an automatically maintained history table for every change to a response
  • An incremental, idempotent MERGE based on a high watermark, so that a survey without new responses is skipped without an API call and a repeated run never produces duplicates
  • Explicit status recording per survey per run (succeeded, skipped, empty or failed) with row counts and error messages in a central log table
  • A workaround for a platform quirk where the overview endpoint reports a status field incorrectly; the sync goes by the responses that are actually there, so archived surveys with history still come along

In detail

  • Schema detection at runtime: columns are discovered per survey from the incoming data, sanitised into valid SQL identifiers
  • A full audit trail through temporal tables: every change to a response stays available without the main table filling up with duplicate rows
  • Incremental and idempotent: a high watermark avoids needless API calls, and the MERGE on a unique ID avoids duplicates and data loss
  • Explicit failure handling: on an error in one survey the high watermark is put back so the next run tries again, while the rest carries on
  • Every run is traceable: the status overview is built from the log table, not from a separate count that can drift out of sync

Outcome

In production and in daily use as the first step of a three-step reporting pipeline.