Problems / Forward-Fill Sensor Readings / Editorial
PARTITION BY sensor_id ORDER BY reading_time
last_value
IGNORE NULLS
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
last_value(value)
last_value(value IGNORE NULLS)
sensor_id
reading_time
In pandas this is df.groupby("sensor_id")["value"].ffill(); the grouping is what stops one sensor's last reading from leaking into the next sensor's leading gap.
df.groupby("sensor_id")["value"].ffill()
In the PySpark variant, F.last("value", ignorenulls=True).over(window) is the canonical Spark idiom, but SQLFrame compiles it to a FILTER (WHERE ...) clause that DuckDB's window parser rejects — the reliable route is F.expr with the native DuckDB window expression.
F.last("value", ignorenulls=True).over(window)
FILTER (WHERE ...)
F.expr
The whole problem hinges on the window frame. With the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) or a full-partition frame, last_value either returns the current row or the partition's final value — both wrong. The combination running-frame + IGNORE NULLS turns last_value into "most recent known value as of this row", which is the precise definition of forward-fill. Partitioning provides the second guarantee: sensor 2's leading NULLs must not inherit sensor 1's final reading.
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
Solve Forward-Fill Sensor Readings yourself →