Scenario C: Industrial IoT telemetry¶
Part of Streaming Transformations › Scenarios.
Goal¶
Industrial devices and gateways often send several readings in one message, and label each measurement with a raw tag ID. Analysts want one typed row per reading, labeled with the engineering name of the measurement, seconds after it arrives.
Transformations used¶
- Lateral Flatten on the stream: expand the array of readings in each message, before the dimension join (derived table).
- Stream enrichment: map each raw tag ID to its engineering name and unit.
- Stream filtering on dimension columns: keep only readings that matched a known tag.
- Insert-triggered materialized views: maintain per-minute rollups per device next to the raw readings.
Source data¶
Stream¶
The example uses these 3 records:
Dimension table¶
The PIPE joins this dimension table, refreshed periodically:
Target table¶
The PIPE lands transformed and filtered rows in this target table, with one row per reading:
Transformation¶
The PIPE synchronously lands data in a materialized view and the target table. Readings within device messages are flattened. Tag IDs are mapped to their engineering name and unit by joining the dimension table. Filtering on a dimension column keeps only readings that match a known tag.
Result¶
Target table¶
Querying the target table returns these rows:
| DEVICE_ID | EVENT_TS | TAG_ID | TAG_NAME | UNIT | READING_VALUE |
|---|---|---|---|---|---|
| press-01 | 2026-10-09 08:00:00 | T100 | spindle_temperature | degC | 71.4 |
| press-01 | 2026-10-09 08:00:00 | T200 | motor_current | A | 12.8 |
| press-01 | 2026-10-09 08:00:00 | T300 | vibration_rms | mm/s | 0.42 |
| press-01 | 2026-10-09 08:00:30 | T100 | spindle_temperature | degC | 72.0 |
| press-01 | 2026-10-09 08:00:30 | T200 | motor_current | A | 13.2 |
| press-02 | 2026-10-09 08:00:00 | T100 | spindle_temperature | degC | 68.9 |
| press-02 | 2026-10-09 08:00:00 | T200 | motor_current | A | 11.1 |
The T999 reading from press-02 is dropped because dim_tags has no matching tag. Each of the other seven readings lands as its own row with its tag name and unit.
Insert-triggered materialized views¶
The PIPE keeps iot_readings_per_minute up to date as it lands rows. The view holds one row per device, tag, and minute, with the average value and the number of readings. Querying it returns these rows:
| DEVICE_ID | TAG_NAME | MINUTE_TS | AVG_VALUE | READING_COUNT |
|---|---|---|---|---|
| press-01 | spindle_temperature | 2026-10-09 08:00:00 | 71.7 | 2 |
| press-01 | motor_current | 2026-10-09 08:00:00 | 13.0 | 2 |
| press-01 | vibration_rms | 2026-10-09 08:00:00 | 0.42 | 1 |
| press-02 | spindle_temperature | 2026-10-09 08:00:00 | 68.9 | 1 |
| press-02 | motor_current | 2026-10-09 08:00:00 | 11.1 | 1 |
The two press-01 records fall in the same minute, so their spindle temperature and motor current readings are combined into one row each, with the average value and a count of 2. As more readings arrive within the same minute, the average and the count are updated.
Considerations¶
- Dimension data is a snapshot that refreshes periodically, so updates can take several minutes to appear. This works well for slow-moving reference data. Dynamic tables can be used as dimension tables.
- A
FLATTENbefore the dimension join must be wrapped in a derived table. INNER JOINisn’t supported. To keep only matched rows, useLEFT OUTER JOINandWHEREon a dimension key withIS NOT NULL.- Each reading becomes its own row, so a message with ten readings writes ten rows. Take this into account when sizing the pipe.
ERROR_LOGGINGcurrently can’t be enabled on the target table of a pipe that usesLATERAL FLATTEN.- Create the materialized views before the pipe. Rows ingested before a view exists aren’t backfilled into it.
See also¶
See Stream filtering, Stream enrichment, Lateral Flatten, and Insert-triggered materialized views for more information on the transformations used in this scenario.
Previous: Scenario B: Observability logs and OpenTelemetry · Next: Scenario D: Security events