What does DEFAULT CURRENT_TIMESTAMP in a CREATE TABLE column definition mean, and when is it evaluated?
answer
- fills a gap left by INSERT
- the clause stores an expression
- evaluated when the row is written
- each row gets its own value
- not frozen at CREATE TABLE time
basics
~20 sDEFAULT names the value the engine stores when an INSERT supplies none for that column. The expression is evaluated at insert time, so each row records its own insertion moment rather than one value frozen when the table was created.
solid answer
~50 s`DEFAULT` is a column option in a `CREATE TABLE` column definition. It stores an **expression** in the catalog, not a pre-computed value, and the engine evaluates that expression when a row is inserted without a value for the column. So `created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP` stamps each row with the time it was inserted — a row added today and one added next year get different values. A literal default such as `status VARCHAR(20) DEFAULT 'NEW'` works the same way: it is re-supplied for every row that omits the column. Standard SQL keeps defaults deliberately narrow — a literal, `NULL`, or a niladic function such as `CURRENT_DATE`, `CURRENT_TIMESTAMP` or `CURRENT_USER`. A default cannot look at other columns of the same row; deriving one column from another is what a generated column is for. Engines differ in how much expression freedom they allow, so check yours before writing anything clever.
code
sql · 9 linesCREATE TABLE orders (
order_id BIGINT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'NEW',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
discount DECIMAL(5,2) DEFAULT 0
);
-- status becomes 'NEW', created_at becomes the time this statement runs
INSERT INTO orders (order_id) VALUES (1);go deeper
Be ready to write a column definition with a default and say plainly that the value is produced when a row is inserted, not when the table is created.
Explain that the catalog stores an expression rather than a value, which defaults standard SQL permits, and why a default cannot reference sibling columns.
Show judgment about which values belong in the schema as defaults versus in application code, and note that changing a default is a migration with its own rollout.
Own the convention: defaults in the schema make behaviour uniform across every writer including ad-hoc SQL, but they also hide logic from application readers. Decide where that line sits for the organisation.
## What DEFAULT declares A `CREATE TABLE` statement is a list of column definitions, each of which is a column name, a data type, and an optional set of column options and constraints. `DEFAULT <value expression>` is one of those options. It records in the catalog an expression the engine will use to produce a value for that column whenever an `INSERT` statement does not provide one. Declaring a default changes nothing else about the column: it does not make the column required, it does not restrict what may later be stored there, and it does not touch rows that already exist. ```sql CREATE TABLE orders ( order_id BIGINT NOT NULL, status VARCHAR(20) DEFAULT 'NEW', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, discount DECIMAL(5,2) DEFAULT 0 ); ``` ## The expression is evaluated at insert time The single most common misunderstanding is that `DEFAULT CURRENT_TIMESTAMP` freezes the moment the table was created. It does not. What the catalog holds is the *expression* `CURRENT_TIMESTAMP`; the engine evaluates it while executing the `INSERT`. A row inserted this morning and a row inserted a year later therefore carry different `created_at` values, which is exactly what makes this a working audit column with no application code involved. The same is true of literal defaults — `DEFAULT 'NEW'` is supplied afresh for each row that omits `status`. One nuance is worth knowing: the datetime value functions are not re-evaluated at every microsecond within a statement. Standard SQL requires that all such functions in a single statement return the same value, and PostgreSQL holds `CURRENT_TIMESTAMP` fixed for the whole transaction. So a 100-row `INSERT` will normally stamp all 100 rows with an identical timestamp. That is per-statement stability, not per-table stability. ## What may legally appear in a DEFAULT Standard SQL keeps the set of allowed defaults small: a literal of a compatible type, the keyword `NULL`, or a niladic (argument-free) built-in such as `CURRENT_DATE`, `CURRENT_TIME`, `CURRENT_TIMESTAMP`, `LOCALTIMESTAMP`, `CURRENT_USER` or `SESSION_USER`. Two things are firmly outside the clause: - **Another column of the same row.** `total DECIMAL(10,2) DEFAULT price * quantity` is not a default; a default must be computable without looking at the rest of the row. A column derived from siblings is a generated (computed) column, a different feature with different syntax. - **Anything requiring the row to already exist.** The default is produced as part of building the row, so it cannot depend on the row's key, its position, or other rows. Engines extend this in different directions. PostgreSQL accepts any expression that does not reference other columns of the table, including function calls. MySQL requires an expression default to be wrapped in parentheses — `DEFAULT (UUID())` — while `DEFAULT CURRENT_TIMESTAMP` is accepted bare. Because the permitted set genuinely differs, treat anything beyond a literal or a datetime function as engine-specific and verify it. ## DEFAULT NULL and no DEFAULT at all For a nullable column the two are equivalent: a column with no `DEFAULT` clause defaults to `NULL`, and writing `DEFAULT NULL` merely documents that. The declaration is worth writing when you want a reader to see that the absence of a default was a decision rather than an oversight. ## What a DEFAULT does not do A default is a convenience for writers, not a guarantee for readers. It says what happens when a value is *missing from the statement*; it does not police what values may be stored, does not make a column mandatory, and does not repair existing rows. If a column must always hold a value, that is `NOT NULL`; if a value must satisfy a rule, that is a `CHECK` constraint. `DEFAULT` and `NOT NULL` are frequently declared together — `created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP` is a standard pairing — precisely because they answer two different questions: what goes in when nothing is offered, and whether nothing is allowed at all. ## Practical guidance Use defaults for the values that are genuinely mechanical: creation timestamps, status columns whose initial state is fixed, counters starting at zero, boolean flags. Keep them simple enough that a reader of the `CREATE TABLE` statement can predict what a row will contain. And remember that the default lives in the schema, so changing it later is a schema change with its own migration, not a code deploy.
- Can a column's DEFAULT reference another column of the same row?No. A default must be computable without inspecting the rest of the row, so `DEFAULT price * quantity` is not legal. Standard SQL restricts defaults to literals, `NULL`, and niladic functions such as `CURRENT_TIMESTAMP`. Deriving one column from others is what a generated (computed) column exists for, or you compute the value in the `INSERT` itself.
- Is DEFAULT NULL different from writing no DEFAULT clause at all?For a nullable column, no — a column with no `DEFAULT` clause already defaults to `NULL`, so the two behave identically. Writing `DEFAULT NULL` is documentation: it shows a reader that the absence of a meaningful default was deliberate. On a `NOT NULL` column, `DEFAULT NULL` is pointless and some engines reject it.
- If a multi-row INSERT relies on DEFAULT CURRENT_TIMESTAMP, do all the rows get the same timestamp?Usually yes. Standard SQL requires every datetime value function in one statement to return the same value, and PostgreSQL keeps `CURRENT_TIMESTAMP` fixed for an entire transaction. So a batch insert typically stamps all its rows identically. If you need genuinely distinct per-row ordering, use a sequence or identity column rather than a timestamp.
saying these in an interview costs you the question
- Says the value is fixed when the table is created
- Thinks DEFAULT makes the column mandatory or non-null
- Claims a DEFAULT can reference another column
- Assumes any function call is a legal default everywhere
- Believes declaring a default updates existing rows