"PostgreSQL 18 Temporal Tables: WITHOUT OVERLAPS Guide"
PostgreSQL 18 temporal tables bring native valid-time modeling: PERIOD columns, WITHOUT OVERLAPS constraints, and temporal foreign keys — plus what happened to FOR PORTION OF.
If you've been searching for postgresql 18 temporal tables , you've probably seen two completely different stories: blog posts celebrating new valid-time constraints, and beta-era posts hyping FOR PORTION OF syntax that no longer exists. Here's the real picture. PostgreSQL 18 (GA since 2025-09-25) shipped native valid-time modeling: PERIOD columns, temporal primary keys and unique constraints with WITHOUT OVERLAPS , and temporal foreign keys. The FOR PORTION OF syntax for UPDATE and DELETE was committed to the PostgreSQL 19 beta cycle — and then reverted. This guide shows you what you can actually use today, with runnable schema code for price histories and subscriptions, and a straight explanation of the FOR PORTION OF revert so you never write dead syntax. Last updated: October 4, 2026 What you'll learn The valid-time vs transaction-time distinction and why Postgres 18 only models one of them PERIOD columns and temporal primary keys with WITHOUT OVERLAPS Temporal foreign keys with PERIOD and how they differ from regular foreign keys A real postgres price history table design with point-in-time queries How the pre-PG18 EXCLUDE USING gist workaround compares Exactly what happened to FOR PORTION OF — and why it's not in PostgreSQL 19 Valid Time vs Transaction Time: The One Distinction That Matters Temporal data comes in two flavors, and confusing them is the most common mistake in this space. Valid time is the period during which a fact is true in the real world. "Product X cost $49 from March 1 to June 1" is a valid-time statement. Your application decides these dates — they come from business logic, price changes, subscription start/end dates. Transaction time (system time) is when the database knew about the fact. "We recorded that price…