How does an INSERT work, and what are the different ways to specify the rows it adds?
An INSERT adds one or more rows to a table. There are three practical forms. You can supply literal values with a VALUES clause, you can copy rows from another table with an INSERT ... SELECT, and you can copy rows from a table in another database with a dialect-specific form such as PostgreSQL's INSERT ... SELECT FROM other_db.schema.table.
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(120) NOT NULL,
email VARCHAR(200) NOT NULL,
city VARCHAR(80),
tier VARCHAR(20) NOT NULL DEFAULT 'standard'
);
-- Form 1: literal values.
INSERT INTO customers (id, name, email, city)
VALUES (1, 'Ada Lovelace', '[email protected]', 'London');
-- Form 2: literal values, leaving the rest to their defaults.
INSERT INTO customers (id, name, email)
VALUES (2, 'Grace Hopper', '[email protected]');
-- Form 3: rows produced by a query.
INSERT INTO customers (id, name, email, city)
SELECT 3, 'Alan Turing', '[email protected]', 'London';
SELECT id, name, email, city, tier FROM customers ORDER BY id;Three rows come back. Rows 1 and 3 have a city, and all three have the tier 'standard' — rows 1 and 3 because the column was not listed and the default applied, and row 2 because the default applied to a column that was omitted entirely.
Two rules govern what happens when you leave a column out. If the column is NOT NULL with no default, the insert fails. If the column allows NULL, it is set to NULL. If it has a DEFAULT, the default is used — and a default expression is evaluated per row, so DEFAULT (datetime('now')) gives each inserted row its own timestamp rather than the time the statement started.
The other thing worth knowing is that the columns you do not list keep whatever value they had, which for a fresh row means the default or NULL. That is why an INSERT with an explicit column list is safer than one without: it makes the statement independent of the table's column order and of any column that might be added later.